blob: 69008a6190cd8073d552dbc5c3e926200149970f [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 Calderone1cb5d022008-09-07 20:58:50 -04009from os import makedirs, symlink
10from 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
Jean-Paul Calderone5075fce2008-09-07 20:18:55 -040014from OpenSSL.SSL import WantReadError, Context, Connection, Error
Jean-Paul Calderone30c09ea2008-03-21 17:04:05 -040015from OpenSSL.SSL import SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD
Rick Deanb71c0d22009-04-01 14:09:23 -050016from OpenSSL.SSL import OP_NO_SSLv2, OP_NO_SSLv3, OP_SINGLE_DH_USE
17from 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
Jean-Paul Calderone4bccf5e2008-12-28 22:50:42 -050020try:
21 from OpenSSL.SSL import OP_NO_QUERY_MTU
22except ImportError:
23 OP_NO_QUERY_MTU = None
24try:
25 from OpenSSL.SSL import OP_COOKIE_EXCHANGE
26except ImportError:
27 OP_COOKIE_EXCHANGE = None
28try:
29 from OpenSSL.SSL import OP_NO_TICKET
30except ImportError:
31 OP_NO_TICKET = None
Jean-Paul Calderone5ef86512008-04-26 19:06:28 -040032
Jean-Paul Calderone30c09ea2008-03-21 17:04:05 -040033
Rick Deanb1ccd562009-07-09 23:52:39 -050034def socket_pair():
35 ''' Establish and return a pair of network sockets connected
36 to each other. '''
37 # Connect a pair of sockets
38 port = socket()
39 port.bind(('', 0))
40 port.listen(1)
41 client = socket()
42 client.setblocking(False)
43 client.connect_ex(port.getsockname())
44 server = port.accept()[0]
45 server.setblocking(False)
46
47 # Let's pass some unencrypted data to make sure our
48 # socket connection is fine.
49 stuff = "I've got a bad feeling about this."
50 server.send(stuff)
51 assert client.recv(1024) == stuff
52 stuff = "What?!?! The First Bank of Alderaan!"
53 client.send(stuff)
54 assert server.recv(1024) == stuff
55
56 return (server, client)
57
58
Jean-Paul Calderone18808652009-07-05 12:54:05 -040059class ContextTests(TestCase):
Jean-Paul Calderone30c09ea2008-03-21 17:04:05 -040060 """
61 Unit tests for L{OpenSSL.SSL.Context}.
62 """
63 def test_method(self):
64 """
65 L{Context} can be instantiated with one of L{SSLv2_METHOD},
66 L{SSLv3_METHOD}, L{SSLv23_METHOD}, or L{TLSv1_METHOD}.
67 """
68 for meth in [SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD]:
69 Context(meth)
70 self.assertRaises(TypeError, Context, "")
71 self.assertRaises(ValueError, Context, 10)
72
73
74 def test_use_privatekey(self):
75 """
76 L{Context.use_privatekey} takes an L{OpenSSL.crypto.PKey} instance.
77 """
78 key = PKey()
79 key.generate_key(TYPE_RSA, 128)
80 ctx = Context(TLSv1_METHOD)
81 ctx.use_privatekey(key)
82 self.assertRaises(TypeError, ctx.use_privatekey, "")
Jean-Paul Calderone828c9cb2008-04-26 18:06:54 -040083
84
85 def test_set_passwd_cb(self):
86 """
87 L{Context.set_passwd_cb} accepts a callable which will be invoked when
88 a private key is loaded from an encrypted PEM.
89 """
90 key = PKey()
91 key.generate_key(TYPE_RSA, 128)
92 pemFile = self.mktemp()
93 fObj = file(pemFile, 'w')
94 passphrase = "foobar"
95 fObj.write(dump_privatekey(FILETYPE_PEM, key, "blowfish", passphrase))
96 fObj.close()
97
98 calledWith = []
99 def passphraseCallback(maxlen, verify, extra):
100 calledWith.append((maxlen, verify, extra))
101 return passphrase
102 context = Context(TLSv1_METHOD)
103 context.set_passwd_cb(passphraseCallback)
104 context.use_privatekey_file(pemFile)
105 self.assertTrue(len(calledWith), 1)
106 self.assertTrue(isinstance(calledWith[0][0], int))
107 self.assertTrue(isinstance(calledWith[0][1], int))
108 self.assertEqual(calledWith[0][2], None)
Jean-Paul Calderone5ef86512008-04-26 19:06:28 -0400109
110
111 def test_set_info_callback(self):
112 """
113 L{Context.set_info_callback} accepts a callable which will be invoked
114 when certain information about an SSL connection is available.
115 """
Rick Deanb1ccd562009-07-09 23:52:39 -0500116 (server, client) = socket_pair()
Jean-Paul Calderone5ef86512008-04-26 19:06:28 -0400117
118 clientSSL = Connection(Context(TLSv1_METHOD), client)
119 clientSSL.set_connect_state()
120
121 called = []
122 def info(conn, where, ret):
123 called.append((conn, where, ret))
124 context = Context(TLSv1_METHOD)
125 context.set_info_callback(info)
126 context.use_certificate(
127 load_certificate(FILETYPE_PEM, cleartextCertificatePEM))
128 context.use_privatekey(
129 load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM))
130
Jean-Paul Calderone5ef86512008-04-26 19:06:28 -0400131 serverSSL = Connection(context, server)
132 serverSSL.set_accept_state()
133
134 while not called:
135 for ssl in clientSSL, serverSSL:
136 try:
137 ssl.do_handshake()
138 except WantReadError:
139 pass
140
141 # Kind of lame. Just make sure it got called somehow.
142 self.assertTrue(called)
Jean-Paul Calderonee1bd4322008-09-07 20:17:17 -0400143
144
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400145 def _load_verify_locations_test(self, *args):
Rick Deanb1ccd562009-07-09 23:52:39 -0500146 (server, client) = socket_pair()
Jean-Paul Calderonee1bd4322008-09-07 20:17:17 -0400147
Jean-Paul Calderonee1bd4322008-09-07 20:17:17 -0400148 clientContext = Context(TLSv1_METHOD)
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400149 clientContext.load_verify_locations(*args)
Jean-Paul Calderonee1bd4322008-09-07 20:17:17 -0400150 # Require that the server certificate verify properly or the
151 # connection will fail.
152 clientContext.set_verify(
153 VERIFY_PEER,
154 lambda conn, cert, errno, depth, preverify_ok: preverify_ok)
155
156 clientSSL = Connection(clientContext, client)
157 clientSSL.set_connect_state()
158
Jean-Paul Calderonee1bd4322008-09-07 20:17:17 -0400159 serverContext = Context(TLSv1_METHOD)
160 serverContext.use_certificate(
161 load_certificate(FILETYPE_PEM, cleartextCertificatePEM))
162 serverContext.use_privatekey(
163 load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM))
164
165 serverSSL = Connection(serverContext, server)
166 serverSSL.set_accept_state()
167
168 for i in range(3):
169 for ssl in clientSSL, serverSSL:
170 try:
171 # Without load_verify_locations above, the handshake
172 # will fail:
173 # Error: [('SSL routines', 'SSL3_GET_SERVER_CERTIFICATE',
174 # 'certificate verify failed')]
175 ssl.do_handshake()
176 except WantReadError:
177 pass
178
179 cert = clientSSL.get_peer_certificate()
Jean-Paul Calderone20131f52009-04-01 12:05:45 -0400180 self.assertEqual(cert.get_subject().CN, 'Testing Root CA')
Jean-Paul Calderone5075fce2008-09-07 20:18:55 -0400181
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400182 def test_load_verify_file(self):
183 """
184 L{Context.load_verify_locations} accepts a file name and uses the
185 certificates within for verification purposes.
186 """
187 cafile = self.mktemp()
188 fObj = file(cafile, 'w')
189 fObj.write(cleartextCertificatePEM)
190 fObj.close()
191
192 self._load_verify_locations_test(cafile)
193
Jean-Paul Calderone5075fce2008-09-07 20:18:55 -0400194
195 def test_load_verify_invalid_file(self):
196 """
197 L{Context.load_verify_locations} raises L{Error} when passed a
198 non-existent cafile.
199 """
200 clientContext = Context(TLSv1_METHOD)
201 self.assertRaises(
202 Error, clientContext.load_verify_locations, self.mktemp())
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400203
204
205 def test_load_verify_directory(self):
206 """
207 L{Context.load_verify_locations} accepts a directory name and uses
208 the certificates within for verification purposes.
209 """
210 capath = self.mktemp()
211 makedirs(capath)
212 cafile = join(capath, 'cert.pem')
213 fObj = file(cafile, 'w')
214 fObj.write(cleartextCertificatePEM)
215 fObj.close()
216
217 # Hash value computed manually with c_rehash to avoid depending on
218 # c_rehash in the test suite.
Jean-Paul Calderone20131f52009-04-01 12:05:45 -0400219 symlink('cert.pem', join(capath, 'c7adac82.0'))
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400220
221 self._load_verify_locations_test(None, capath)
222
223
224 def test_set_default_verify_paths(self):
225 """
226 L{Context.set_default_verify_paths} causes the platform-specific CA
227 certificate locations to be used for verification purposes.
228 """
229 # Testing this requires a server with a certificate signed by one of
230 # the CAs in the platform CA location. Getting one of those costs
231 # money. Fortunately (or unfortunately, depending on your
232 # perspective), it's easy to think of a public server on the
233 # internet which has such a certificate. Connecting to the network
234 # in a unit test is bad, but it's the only way I can think of to
235 # really test this. -exarkun
236
237 # Arg, verisign.com doesn't speak TLSv1
238 context = Context(SSLv3_METHOD)
239 context.set_default_verify_paths()
240 context.set_verify(
241 VERIFY_PEER,
242 lambda conn, cert, errno, depth, preverify_ok: preverify_ok)
243
244 client = socket()
245 client.connect(('verisign.com', 443))
246 clientSSL = Connection(context, client)
247 clientSSL.set_connect_state()
248 clientSSL.do_handshake()
249 clientSSL.send('GET / HTTP/1.0\r\n\r\n')
250 self.assertTrue(clientSSL.recv(1024))
Jean-Paul Calderone52f0d8b2009-03-07 09:10:19 -0500251 if platform == "darwin":
Jean-Paul Calderone1d287e52009-03-07 09:09:07 -0500252 test_set_default_verify_paths.todo = (
253 "set_default_verify_paths appears not to work on OS X - a "
254 "problem with the supplied OpenSSL, perhaps?")
Jean-Paul Calderone9eadb962008-09-07 21:20:44 -0400255
256
257 def test_set_default_verify_paths_signature(self):
258 """
259 L{Context.set_default_verify_paths} takes no arguments and raises
260 L{TypeError} if given any.
261 """
262 context = Context(TLSv1_METHOD)
263 self.assertRaises(TypeError, context.set_default_verify_paths, None)
264 self.assertRaises(TypeError, context.set_default_verify_paths, 1)
265 self.assertRaises(TypeError, context.set_default_verify_paths, "")
Jean-Paul Calderone327d8f92008-12-28 21:55:56 -0500266
267
268
269class ConstantsTests(TestCase):
270 """
271 Tests for the values of constants exposed in L{OpenSSL.SSL}.
272
273 These are values defined by OpenSSL intended only to be used as flags to
274 OpenSSL APIs. The only assertions it seems can be made about them is
275 their values.
276 """
Jean-Paul Calderoned811b682008-12-28 22:59:15 -0500277 # unittest.TestCase has no skip mechanism
278 if OP_NO_QUERY_MTU is not None:
279 def test_op_no_query_mtu(self):
280 """
281 The value of L{OpenSSL.SSL.OP_NO_QUERY_MTU} is 0x1000, the value of
282 I{SSL_OP_NO_QUERY_MTU} defined by I{openssl/ssl.h}.
283 """
284 self.assertEqual(OP_NO_QUERY_MTU, 0x1000)
285 else:
286 "OP_NO_QUERY_MTU unavailable - OpenSSL version may be too old"
Jean-Paul Calderone327d8f92008-12-28 21:55:56 -0500287
288
Jean-Paul Calderoned811b682008-12-28 22:59:15 -0500289 if OP_COOKIE_EXCHANGE is not None:
290 def test_op_cookie_exchange(self):
291 """
292 The value of L{OpenSSL.SSL.OP_COOKIE_EXCHANGE} is 0x2000, the value
293 of I{SSL_OP_COOKIE_EXCHANGE} defined by I{openssl/ssl.h}.
294 """
295 self.assertEqual(OP_COOKIE_EXCHANGE, 0x2000)
296 else:
297 "OP_COOKIE_EXCHANGE unavailable - OpenSSL version may be too old"
Jean-Paul Calderone327d8f92008-12-28 21:55:56 -0500298
299
Jean-Paul Calderoned811b682008-12-28 22:59:15 -0500300 if OP_NO_TICKET is not None:
301 def test_op_no_ticket(self):
302 """
303 The value of L{OpenSSL.SSL.OP_NO_TICKET} is 0x4000, the value of
304 I{SSL_OP_NO_TICKET} defined by I{openssl/ssl.h}.
305 """
306 self.assertEqual(OP_NO_TICKET, 0x4000)
307 else:
308 "OP_NO_TICKET unavailable - OpenSSL version may be too old"
Rick Dean5b7b6372009-04-01 11:34:06 -0500309
310
Jean-Paul Calderoneeeee26a2009-04-27 11:24:30 -0400311
Rick Deanb71c0d22009-04-01 14:09:23 -0500312root_cert_pem = """-----BEGIN CERTIFICATE-----
313MIIC7TCCAlagAwIBAgIIPQzE4MbeufQwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UE
314BhMCVVMxCzAJBgNVBAgTAklMMRAwDgYDVQQHEwdDaGljYWdvMRAwDgYDVQQKEwdU
315ZXN0aW5nMRgwFgYDVQQDEw9UZXN0aW5nIFJvb3QgQ0EwIhgPMjAwOTAzMjUxMjM2
316NThaGA8yMDE3MDYxMTEyMzY1OFowWDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAklM
317MRAwDgYDVQQHEwdDaGljYWdvMRAwDgYDVQQKEwdUZXN0aW5nMRgwFgYDVQQDEw9U
318ZXN0aW5nIFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPmaQumL
319urpE527uSEHdL1pqcDRmWzu+98Y6YHzT/J7KWEamyMCNZ6fRW1JCR782UQ8a07fy
3202xXsKy4WdKaxyG8CcatwmXvpvRQ44dSANMihHELpANTdyVp6DCysED6wkQFurHlF
3211dshEaJw8b/ypDhmbVIo6Ci1xvCJqivbLFnbAgMBAAGjgbswgbgwHQYDVR0OBBYE
322FINVdy1eIfFJDAkk51QJEo3IfgSuMIGIBgNVHSMEgYAwfoAUg1V3LV4h8UkMCSTn
323VAkSjch+BK6hXKRaMFgxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UE
324BxMHQ2hpY2FnbzEQMA4GA1UEChMHVGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBS
325b290IENBggg9DMTgxt659DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GB
326AGGCDazMJGoWNBpc03u6+smc95dEead2KlZXBATOdFT1VesY3+nUOqZhEhTGlDMi
327hkgaZnzoIq/Uamidegk4hirsCT/R+6vsKAAxNTcBjUeZjlykCJWy5ojShGftXIKY
328w/njVbKMXrvc83qmTdGl3TAM0fxQIpqgcglFLveEBgzn
329-----END CERTIFICATE-----
330"""
331
332root_key_pem = """-----BEGIN RSA PRIVATE KEY-----
333MIICXQIBAAKBgQD5mkLpi7q6ROdu7khB3S9aanA0Zls7vvfGOmB80/yeylhGpsjA
334jWen0VtSQke/NlEPGtO38tsV7CsuFnSmschvAnGrcJl76b0UOOHUgDTIoRxC6QDU
3353claegwsrBA+sJEBbqx5RdXbIRGicPG/8qQ4Zm1SKOgotcbwiaor2yxZ2wIDAQAB
336AoGBAPCgMpmLxzwDaUmcFbTJUvlLW1hoxNNYSu2jIZm1k/hRAcE60JYwvBkgz3UB
337yMEh0AtLxYe0bFk6EHah11tMUPgscbCq73snJ++8koUw+csk22G65hOs51bVb7Aa
3386JBe67oLzdtvgCUFAA2qfrKzWRZzAdhUirQUZgySZk+Xq1pBAkEA/kZG0A6roTSM
339BVnx7LnPfsycKUsTumorpXiylZJjTi9XtmzxhrYN6wgZlDOOwOLgSQhszGpxVoMD
340u3gByT1b2QJBAPtL3mSKdvwRu/+40zaZLwvSJRxaj0mcE4BJOS6Oqs/hS1xRlrNk
341PpQ7WJ4yM6ZOLnXzm2mKyxm50Mv64109FtMCQQDOqS2KkjHaLowTGVxwC0DijMfr
342I9Lf8sSQk32J5VWCySWf5gGTfEnpmUa41gKTMJIbqZZLucNuDcOtzUaeWZlZAkA8
343ttXigLnCqR486JDPTi9ZscoZkZ+w7y6e/hH8t6d5Vjt48JVyfjPIaJY+km58LcN3
3446AWSeGAdtRFHVzR7oHjVAkB4hutvxiOeiIVQNBhM6RSI9aBPMI21DoX2JRoxvNW2
345cbvAhow217X9V0dVerEOKxnNYspXRrh36h7k4mQA+sDq
346-----END RSA PRIVATE KEY-----
347"""
348
349server_cert_pem = """-----BEGIN CERTIFICATE-----
350MIICKDCCAZGgAwIBAgIJAJn/HpR21r/8MA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
351BAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEQMA4GA1UEChMH
352VGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBSb290IENBMCIYDzIwMDkwMzI1MTIz
353NzUzWhgPMjAxNzA2MTExMjM3NTNaMBgxFjAUBgNVBAMTDWxvdmVseSBzZXJ2ZXIw
354gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAL6m+G653V0tpBC/OKl22VxOi2Cv
355lK4TYu9LHSDP9uDVTe7V5D5Tl6qzFoRRx5pfmnkqT5B+W9byp2NU3FC5hLm5zSAr
356b45meUhjEJ/ifkZgbNUjHdBIGP9MAQUHZa5WKdkGIJvGAvs8UzUqlr4TBWQIB24+
357lJ+Ukk/CRgasrYwdAgMBAAGjNjA0MB0GA1UdDgQWBBS4kC7Ij0W1TZXZqXQFAM2e
358gKEG2DATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQUFAAOBgQBh30Li
359dJ+NlxIOx5343WqIBka3UbsOb2kxWrbkVCrvRapCMLCASO4FqiKWM+L0VDBprqIp
3602mgpFQ6FHpoIENGvJhdEKpptQ5i7KaGhnDNTfdy3x1+h852G99f1iyj0RmbuFcM8
361uzujnS8YXWvM7DM1Ilozk4MzPug8jzFp5uhKCQ==
362-----END CERTIFICATE-----
363"""
364
365server_key_pem = """-----BEGIN RSA PRIVATE KEY-----
366MIICWwIBAAKBgQC+pvhuud1dLaQQvzipdtlcTotgr5SuE2LvSx0gz/bg1U3u1eQ+
367U5eqsxaEUceaX5p5Kk+QflvW8qdjVNxQuYS5uc0gK2+OZnlIYxCf4n5GYGzVIx3Q
368SBj/TAEFB2WuVinZBiCbxgL7PFM1Kpa+EwVkCAduPpSflJJPwkYGrK2MHQIDAQAB
369AoGAbwuZ0AR6JveahBaczjfnSpiFHf+mve2UxoQdpyr6ROJ4zg/PLW5K/KXrC48G
370j6f3tXMrfKHcpEoZrQWUfYBRCUsGD5DCazEhD8zlxEHahIsqpwA0WWssJA2VOLEN
371j6DuV2pCFbw67rfTBkTSo32ahfXxEKev5KswZk0JIzH3ooECQQDgzS9AI89h0gs8
372Dt+1m11Rzqo3vZML7ZIyGApUzVan+a7hbc33nbGRkAXjHaUBJO31it/H6dTO+uwX
373msWwNG5ZAkEA2RyFKs5xR5USTFaKLWCgpH/ydV96KPOpBND7TKQx62snDenFNNbn
374FwwOhpahld+vqhYk+pfuWWUpQciE+Bu7ZQJASjfT4sQv4qbbKK/scePicnDdx9th
3754e1EeB9xwb+tXXXUo/6Bor/AcUNwfiQ6Zt9PZOK9sR3lMZSsP7rMi7kzuQJABie6
3761sXXjFH7nNJvRG4S39cIxq8YRYTy68II/dlB2QzGpKxV/POCxbJ/zu0CU79tuYK7
377NaeNCFfH3aeTrX0LyQJAMBWjWmeKM2G2sCExheeQK0ROnaBC8itCECD4Jsve4nqf
378r50+LF74iLXFwqysVCebPKMOpDWp/qQ1BbJQIPs7/A==
379-----END RSA PRIVATE KEY-----
380"""
381
382client_cert_pem = """-----BEGIN CERTIFICATE-----
383MIICJjCCAY+gAwIBAgIJAKxpFI5lODkjMA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
384BAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEQMA4GA1UEChMH
385VGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBSb290IENBMCIYDzIwMDkwMzI1MTIz
386ODA1WhgPMjAxNzA2MTExMjM4MDVaMBYxFDASBgNVBAMTC3VnbHkgY2xpZW50MIGf
387MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAZh/SRtNm5ntMT4qb6YzEpTroMlq2
388rn+GrRHRiZ+xkCw/CGNhbtPir7/QxaUj26BSmQrHw1bGKEbPsWiW7bdXSespl+xK
389iku4G/KvnnmWdeJHqsiXeUZtqurMELcPQAw9xPHEuhqqUJvvEoMTsnCEqGM+7Dtb
390oCRajYyHfluARQIDAQABozYwNDAdBgNVHQ4EFgQUNQB+qkaOaEVecf1J3TTUtAff
3910fAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADgYEAyv/Jh7gM
392Q3OHvmsFEEvRI+hsW8y66zK4K5de239Y44iZrFYkt7Q5nBPMEWDj4F2hLYWL/qtI
3939Zdr0U4UDCU9SmmGYh4o7R4TZ5pGFvBYvjhHbkSFYFQXZxKUi+WUxplP6I0wr2KJ
394PSTJCjJOn3xo2NTKRgV1gaoTf2EhL+RG8TQ=
395-----END CERTIFICATE-----
396"""
397
398client_key_pem = """-----BEGIN RSA PRIVATE KEY-----
399MIICXgIBAAKBgQDAZh/SRtNm5ntMT4qb6YzEpTroMlq2rn+GrRHRiZ+xkCw/CGNh
400btPir7/QxaUj26BSmQrHw1bGKEbPsWiW7bdXSespl+xKiku4G/KvnnmWdeJHqsiX
401eUZtqurMELcPQAw9xPHEuhqqUJvvEoMTsnCEqGM+7DtboCRajYyHfluARQIDAQAB
402AoGATkZ+NceY5Glqyl4mD06SdcKfV65814vg2EL7V9t8+/mi9rYL8KztSXGlQWPX
403zuHgtRoMl78yQ4ZJYOBVo+nsx8KZNRCEBlE19bamSbQLCeQMenWnpeYyQUZ908gF
404h6L9qsFVJepgA9RDgAjyDoS5CaWCdCCPCH2lDkdcqC54SVUCQQDseuduc4wi8h4t
405V8AahUn9fn9gYfhoNuM0gdguTA0nPLVWz4hy1yJiWYQe0H7NLNNTmCKiLQaJpAbb
406TC6vE8C7AkEA0Ee8CMJUc20BnGEmxwgWcVuqFWaKCo8jTH1X38FlATUsyR3krjW2
407dL3yDD9NwHxsYP7nTKp/U8MV7U9IBn4y/wJBAJl7H0/BcLeRmuJk7IqJ7b635iYB
408D/9beFUw3MUXmQXZUfyYz39xf6CDZsu1GEdEC5haykeln3Of4M9d/4Kj+FcCQQCY
409si6xwT7GzMDkk/ko684AV3KPc/h6G0yGtFIrMg7J3uExpR/VdH2KgwMkZXisSMvw
410JJEQjOMCVsEJlRk54WWjAkEAzoZNH6UhDdBK5F38rVt/y4SEHgbSfJHIAmPS32Kq
411f6GGcfNpip0Uk7q7udTKuX7Q/buZi/C4YW7u3VKAquv9NA==
412-----END RSA PRIVATE KEY-----
413"""
414
415def verify_cb(conn, cert, errnum, depth, ok):
416 return ok
417
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400418class MemoryBIOTests(TestCase):
Rick Deanb71c0d22009-04-01 14:09:23 -0500419 """
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400420 Tests for L{OpenSSL.SSL.Connection} using a memory BIO.
Rick Deanb71c0d22009-04-01 14:09:23 -0500421 """
Rick Deanb1ccd562009-07-09 23:52:39 -0500422 def _server(self, sock=None):
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400423 # Create the server side Connection. This is mostly setup boilerplate
424 # - use TLSv1, use a particular certificate, etc.
425 server_ctx = Context(TLSv1_METHOD)
426 server_ctx.set_options(OP_NO_SSLv2 | OP_NO_SSLv3 | OP_SINGLE_DH_USE )
427 server_ctx.set_verify(VERIFY_PEER|VERIFY_FAIL_IF_NO_PEER_CERT|VERIFY_CLIENT_ONCE, verify_cb)
428 server_store = server_ctx.get_cert_store()
429 server_ctx.use_privatekey(load_privatekey(FILETYPE_PEM, server_key_pem))
430 server_ctx.use_certificate(load_certificate(FILETYPE_PEM, server_cert_pem))
431 server_ctx.check_privatekey()
432 server_store.add_cert(load_certificate(FILETYPE_PEM, root_cert_pem))
Rick Deanb1ccd562009-07-09 23:52:39 -0500433 # Here the Connection is actually created. If None is passed as the 2nd
434 # parameter, it indicates a memory BIO should be created.
435 server_conn = Connection(server_ctx, sock)
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400436 server_conn.set_accept_state()
437 return server_conn
438
439
Rick Deanb1ccd562009-07-09 23:52:39 -0500440 def _client(self, sock=None):
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400441 # Now create the client side Connection. Similar boilerplate to the above.
442 client_ctx = Context(TLSv1_METHOD)
443 client_ctx.set_options(OP_NO_SSLv2 | OP_NO_SSLv3 | OP_SINGLE_DH_USE )
444 client_ctx.set_verify(VERIFY_PEER|VERIFY_FAIL_IF_NO_PEER_CERT|VERIFY_CLIENT_ONCE, verify_cb)
445 client_store = client_ctx.get_cert_store()
446 client_ctx.use_privatekey(load_privatekey(FILETYPE_PEM, client_key_pem))
447 client_ctx.use_certificate(load_certificate(FILETYPE_PEM, client_cert_pem))
448 client_ctx.check_privatekey()
449 client_store.add_cert(load_certificate(FILETYPE_PEM, root_cert_pem))
Rick Deanb1ccd562009-07-09 23:52:39 -0500450 client_conn = Connection(client_ctx, sock)
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400451 client_conn.set_connect_state()
452 return client_conn
453
454
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400455 def _loopback(self, client_conn, server_conn):
456 """
457 Try to read application bytes from each of the two L{Connection}
458 objects. Copy bytes back and forth between their send/receive buffers
459 for as long as there is anything to copy. When there is nothing more
460 to copy, return C{None}. If one of them actually manages to deliver
461 some application bytes, return a two-tuple of the connection from which
462 the bytes were read and the bytes themselves.
463 """
464 wrote = True
465 while wrote:
466 # Loop until neither side has anything to say
467 wrote = False
468
469 # Copy stuff from each side's send buffer to the other side's
470 # receive buffer.
471 for (read, write) in [(client_conn, server_conn),
472 (server_conn, client_conn)]:
473
474 # Give the side a chance to generate some more bytes, or
475 # succeed.
476 try:
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400477 bytes = read.recv(2 ** 16)
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400478 except WantReadError:
479 # It didn't succeed, so we'll hope it generated some
480 # output.
481 pass
482 else:
483 # It did succeed, so we'll stop now and let the caller deal
484 # with it.
485 return (read, bytes)
486
487 while True:
488 # Keep copying as long as there's more stuff there.
489 try:
490 dirty = read.bio_read(4096)
491 except WantReadError:
492 # Okay, nothing more waiting to be sent. Stop
493 # processing this send buffer.
494 break
495 else:
496 # Keep track of the fact that someone generated some
497 # output.
498 wrote = True
499 write.bio_write(dirty)
500
501
Rick Deanb71c0d22009-04-01 14:09:23 -0500502 def test_connect(self):
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400503 """
504 Two L{Connection}s which use memory BIOs can be manually connected by
505 reading from the output of each and writing those bytes to the input of
506 the other and in this way establish a connection and exchange
507 application-level bytes with each other.
508 """
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400509 server_conn = self._server()
510 client_conn = self._client()
Rick Deanb71c0d22009-04-01 14:09:23 -0500511
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400512 # There should be no key or nonces yet.
513 self.assertIdentical(server_conn.master_key(), None)
514 self.assertIdentical(server_conn.client_random(), None)
515 self.assertIdentical(server_conn.server_random(), None)
Rick Deanb71c0d22009-04-01 14:09:23 -0500516
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400517 # First, the handshake needs to happen. We'll deliver bytes back and
518 # forth between the client and server until neither of them feels like
519 # speaking any more.
520 self.assertIdentical(self._loopback(client_conn, server_conn), None)
521
522 # Now that the handshake is done, there should be a key and nonces.
523 self.assertNotIdentical(server_conn.master_key(), None)
524 self.assertNotIdentical(server_conn.client_random(), None)
525 self.assertNotIdentical(server_conn.server_random(), None)
Jean-Paul Calderone6c051e62009-07-05 13:50:34 -0400526 self.assertEquals(server_conn.client_random(), client_conn.client_random())
527 self.assertEquals(server_conn.server_random(), client_conn.server_random())
528 self.assertNotEquals(server_conn.client_random(), server_conn.server_random())
529 self.assertNotEquals(client_conn.client_random(), client_conn.server_random())
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400530
531 # Here are the bytes we'll try to send.
Rick Deanb71c0d22009-04-01 14:09:23 -0500532 important_message = 'One if by land, two if by sea.'
533
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400534 server_conn.write(important_message)
535 self.assertEquals(
536 self._loopback(client_conn, server_conn),
537 (client_conn, important_message))
538
539 client_conn.write(important_message[::-1])
540 self.assertEquals(
541 self._loopback(client_conn, server_conn),
542 (server_conn, important_message[::-1]))
Rick Deanb71c0d22009-04-01 14:09:23 -0500543
544
Rick Deanb1ccd562009-07-09 23:52:39 -0500545 def test_socket_connect(self):
546 """
547 Just like test_connect() but with an actual socket.
548 """
549 (server, client) = socket_pair()
550
551 # Let the encryption begin...
552 client_conn = self._client(client)
553 client_conn.set_connect_state()
554 server_conn = self._server(server)
555 server_conn.set_accept_state()
556 # Establish the connection
557 established = False
558 while not established:
559 established = True # assume the best
560 for ssl in client_conn, server_conn:
561 try:
562 # Generally a recv() or send() could also work instead
563 # of do_handshake(), and we would stop on the first
564 # non-exception.
565 ssl.do_handshake()
566 except WantReadError:
567 established = False
568
569 important_message = "Help me Obi Wan Kenobi, you're my only hope."
570 client_conn.send(important_message)
571 msg = server_conn.recv(1024)
572 self.assertEqual(msg, important_message)
573
574 # Again in the other direction, just for fun.
575 important_message = important_message[::-1]
576 server_conn.send(important_message)
577 msg = client_conn.recv(1024)
578 self.assertEqual(msg, important_message)
579
580
Jean-Paul Calderonefc4ed0f2009-04-27 11:51:27 -0400581 def test_socketOverridesMemory(self):
Rick Deanb71c0d22009-04-01 14:09:23 -0500582 """
583 Test that L{OpenSSL.SSL.bio_read} and L{OpenSSL.SSL.bio_write} don't
584 work on L{OpenSSL.SSL.Connection}() that use sockets.
585 """
586 context = Context(SSLv3_METHOD)
587 client = socket()
588 clientSSL = Connection(context, client)
589 self.assertRaises( TypeError, clientSSL.bio_read, 100)
590 self.assertRaises( TypeError, clientSSL.bio_write, "foo")
Jean-Paul Calderone07acf3f2009-05-05 13:23:28 -0400591 self.assertRaises( TypeError, clientSSL.bio_shutdown )
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400592
593
594 def test_outgoingOverflow(self):
595 """
596 If more bytes than can be written to the memory BIO are passed to
597 L{Connection.send} at once, the number of bytes which were written is
598 returned and that many bytes from the beginning of the input can be
599 read from the other end of the connection.
600 """
601 server = self._server()
602 client = self._client()
603
604 self._loopback(client, server)
605
606 size = 2 ** 15
607 sent = client.send("x" * size)
608 # Sanity check. We're trying to test what happens when the entire
609 # input can't be sent. If the entire input was sent, this test is
610 # meaningless.
611 self.assertTrue(sent < size)
612
613 receiver, received = self._loopback(client, server)
614 self.assertIdentical(receiver, server)
615
616 # We can rely on all of these bytes being received at once because
617 # _loopback passes 2 ** 16 to recv - more than 2 ** 15.
618 self.assertEquals(len(received), sent)
Jean-Paul Calderone3ad85d42009-04-30 20:24:35 -0400619
620
621 def test_shutdown(self):
622 """
623 L{Connection.bio_shutdown} signals the end of the data stream from
624 which the L{Connection} reads.
625 """
626 server = self._server()
627 server.bio_shutdown()
628 e = self.assertRaises(Error, server.recv, 1024)
629 # We don't want WantReadError or ZeroReturnError or anything - it's a
630 # handshake failure.
631 self.assertEquals(e.__class__, Error)
Jean-Paul Calderone0b88b6a2009-07-05 12:44:41 -0400632
633
634
635if __name__ == '__main__':
636 main()