blob: 70b008a700ad0ecf207da22aee33561cfadd3f66 [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 Calderone828c9cb2008-04-26 18:06:54 -04008from tempfile import mktemp
Jean-Paul Calderone5ef86512008-04-26 19:06:28 -04009from socket import socket
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -040010from os import makedirs, symlink
11from os.path import join
Jean-Paul Calderone0b88b6a2009-07-05 12:44:41 -040012from unittest import main
Jean-Paul Calderone460cc1f2009-03-07 11:31:12 -050013
Jean-Paul Calderone5ef86512008-04-26 19:06:28 -040014from OpenSSL.crypto import TYPE_RSA, FILETYPE_PEM, PKey, dump_privatekey, load_certificate, load_privatekey
Jean-Paul Calderone5075fce2008-09-07 20:18:55 -040015from OpenSSL.SSL import WantReadError, Context, Connection, Error
Jean-Paul Calderone30c09ea2008-03-21 17:04:05 -040016from OpenSSL.SSL import SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD
Rick Deanb71c0d22009-04-01 14:09:23 -050017from OpenSSL.SSL import OP_NO_SSLv2, OP_NO_SSLv3, OP_SINGLE_DH_USE
18from OpenSSL.SSL import VERIFY_PEER, VERIFY_FAIL_IF_NO_PEER_CERT, VERIFY_CLIENT_ONCE
Jean-Paul Calderone0b88b6a2009-07-05 12:44:41 -040019from OpenSSL.test.util import TestCase
Jean-Paul Calderone18808652009-07-05 12:54:05 -040020from OpenSSL.test.test_crypto import cleartextCertificatePEM, cleartextPrivateKeyPEM
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
Jean-Paul Calderone18808652009-07-05 12:54:05 -040035class ContextTests(TestCase):
Jean-Paul Calderone30c09ea2008-03-21 17:04:05 -040036 """
37 Unit tests for L{OpenSSL.SSL.Context}.
38 """
Jean-Paul Calderone828c9cb2008-04-26 18:06:54 -040039 def mktemp(self):
40 """
41 Pathetic substitute for twisted.trial.unittest.TestCase.mktemp.
42 """
43 return mktemp(dir=".")
44
45
Jean-Paul Calderone30c09ea2008-03-21 17:04:05 -040046 def test_method(self):
47 """
48 L{Context} can be instantiated with one of L{SSLv2_METHOD},
49 L{SSLv3_METHOD}, L{SSLv23_METHOD}, or L{TLSv1_METHOD}.
50 """
51 for meth in [SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD]:
52 Context(meth)
53 self.assertRaises(TypeError, Context, "")
54 self.assertRaises(ValueError, Context, 10)
55
56
57 def test_use_privatekey(self):
58 """
59 L{Context.use_privatekey} takes an L{OpenSSL.crypto.PKey} instance.
60 """
61 key = PKey()
62 key.generate_key(TYPE_RSA, 128)
63 ctx = Context(TLSv1_METHOD)
64 ctx.use_privatekey(key)
65 self.assertRaises(TypeError, ctx.use_privatekey, "")
Jean-Paul Calderone828c9cb2008-04-26 18:06:54 -040066
67
68 def test_set_passwd_cb(self):
69 """
70 L{Context.set_passwd_cb} accepts a callable which will be invoked when
71 a private key is loaded from an encrypted PEM.
72 """
73 key = PKey()
74 key.generate_key(TYPE_RSA, 128)
75 pemFile = self.mktemp()
76 fObj = file(pemFile, 'w')
77 passphrase = "foobar"
78 fObj.write(dump_privatekey(FILETYPE_PEM, key, "blowfish", passphrase))
79 fObj.close()
80
81 calledWith = []
82 def passphraseCallback(maxlen, verify, extra):
83 calledWith.append((maxlen, verify, extra))
84 return passphrase
85 context = Context(TLSv1_METHOD)
86 context.set_passwd_cb(passphraseCallback)
87 context.use_privatekey_file(pemFile)
88 self.assertTrue(len(calledWith), 1)
89 self.assertTrue(isinstance(calledWith[0][0], int))
90 self.assertTrue(isinstance(calledWith[0][1], int))
91 self.assertEqual(calledWith[0][2], None)
Jean-Paul Calderone5ef86512008-04-26 19:06:28 -040092
93
94 def test_set_info_callback(self):
95 """
96 L{Context.set_info_callback} accepts a callable which will be invoked
97 when certain information about an SSL connection is available.
98 """
99 port = socket()
100 port.bind(('', 0))
101 port.listen(1)
102
103 client = socket()
104 client.setblocking(False)
105 client.connect_ex(port.getsockname())
106
107 clientSSL = Connection(Context(TLSv1_METHOD), client)
108 clientSSL.set_connect_state()
109
110 called = []
111 def info(conn, where, ret):
112 called.append((conn, where, ret))
113 context = Context(TLSv1_METHOD)
114 context.set_info_callback(info)
115 context.use_certificate(
116 load_certificate(FILETYPE_PEM, cleartextCertificatePEM))
117 context.use_privatekey(
118 load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM))
119
120 server, ignored = port.accept()
121 server.setblocking(False)
122
123 serverSSL = Connection(context, server)
124 serverSSL.set_accept_state()
125
126 while not called:
127 for ssl in clientSSL, serverSSL:
128 try:
129 ssl.do_handshake()
130 except WantReadError:
131 pass
132
133 # Kind of lame. Just make sure it got called somehow.
134 self.assertTrue(called)
Jean-Paul Calderonee1bd4322008-09-07 20:17:17 -0400135
136
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400137 def _load_verify_locations_test(self, *args):
Jean-Paul Calderonee1bd4322008-09-07 20:17:17 -0400138 port = socket()
139 port.bind(('', 0))
140 port.listen(1)
141
142 client = socket()
143 client.setblocking(False)
144 client.connect_ex(port.getsockname())
145
Jean-Paul Calderonee1bd4322008-09-07 20:17:17 -0400146 clientContext = Context(TLSv1_METHOD)
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400147 clientContext.load_verify_locations(*args)
Jean-Paul Calderonee1bd4322008-09-07 20:17:17 -0400148 # Require that the server certificate verify properly or the
149 # connection will fail.
150 clientContext.set_verify(
151 VERIFY_PEER,
152 lambda conn, cert, errno, depth, preverify_ok: preverify_ok)
153
154 clientSSL = Connection(clientContext, client)
155 clientSSL.set_connect_state()
156
157 server, _ = port.accept()
158 server.setblocking(False)
159
160 serverContext = Context(TLSv1_METHOD)
161 serverContext.use_certificate(
162 load_certificate(FILETYPE_PEM, cleartextCertificatePEM))
163 serverContext.use_privatekey(
164 load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM))
165
166 serverSSL = Connection(serverContext, server)
167 serverSSL.set_accept_state()
168
169 for i in range(3):
170 for ssl in clientSSL, serverSSL:
171 try:
172 # Without load_verify_locations above, the handshake
173 # will fail:
174 # Error: [('SSL routines', 'SSL3_GET_SERVER_CERTIFICATE',
175 # 'certificate verify failed')]
176 ssl.do_handshake()
177 except WantReadError:
178 pass
179
180 cert = clientSSL.get_peer_certificate()
Jean-Paul Calderone20131f52009-04-01 12:05:45 -0400181 self.assertEqual(cert.get_subject().CN, 'Testing Root CA')
Jean-Paul Calderone5075fce2008-09-07 20:18:55 -0400182
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400183 def test_load_verify_file(self):
184 """
185 L{Context.load_verify_locations} accepts a file name and uses the
186 certificates within for verification purposes.
187 """
188 cafile = self.mktemp()
189 fObj = file(cafile, 'w')
190 fObj.write(cleartextCertificatePEM)
191 fObj.close()
192
193 self._load_verify_locations_test(cafile)
194
Jean-Paul Calderone5075fce2008-09-07 20:18:55 -0400195
196 def test_load_verify_invalid_file(self):
197 """
198 L{Context.load_verify_locations} raises L{Error} when passed a
199 non-existent cafile.
200 """
201 clientContext = Context(TLSv1_METHOD)
202 self.assertRaises(
203 Error, clientContext.load_verify_locations, self.mktemp())
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400204
205
206 def test_load_verify_directory(self):
207 """
208 L{Context.load_verify_locations} accepts a directory name and uses
209 the certificates within for verification purposes.
210 """
211 capath = self.mktemp()
212 makedirs(capath)
213 cafile = join(capath, 'cert.pem')
214 fObj = file(cafile, 'w')
215 fObj.write(cleartextCertificatePEM)
216 fObj.close()
217
218 # Hash value computed manually with c_rehash to avoid depending on
219 # c_rehash in the test suite.
Jean-Paul Calderone20131f52009-04-01 12:05:45 -0400220 symlink('cert.pem', join(capath, 'c7adac82.0'))
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400221
222 self._load_verify_locations_test(None, capath)
223
224
225 def test_set_default_verify_paths(self):
226 """
227 L{Context.set_default_verify_paths} causes the platform-specific CA
228 certificate locations to be used for verification purposes.
229 """
230 # Testing this requires a server with a certificate signed by one of
231 # the CAs in the platform CA location. Getting one of those costs
232 # money. Fortunately (or unfortunately, depending on your
233 # perspective), it's easy to think of a public server on the
234 # internet which has such a certificate. Connecting to the network
235 # in a unit test is bad, but it's the only way I can think of to
236 # really test this. -exarkun
237
238 # Arg, verisign.com doesn't speak TLSv1
239 context = Context(SSLv3_METHOD)
240 context.set_default_verify_paths()
241 context.set_verify(
242 VERIFY_PEER,
243 lambda conn, cert, errno, depth, preverify_ok: preverify_ok)
244
245 client = socket()
246 client.connect(('verisign.com', 443))
247 clientSSL = Connection(context, client)
248 clientSSL.set_connect_state()
249 clientSSL.do_handshake()
250 clientSSL.send('GET / HTTP/1.0\r\n\r\n')
251 self.assertTrue(clientSSL.recv(1024))
Jean-Paul Calderone52f0d8b2009-03-07 09:10:19 -0500252 if platform == "darwin":
Jean-Paul Calderone1d287e52009-03-07 09:09:07 -0500253 test_set_default_verify_paths.todo = (
254 "set_default_verify_paths appears not to work on OS X - a "
255 "problem with the supplied OpenSSL, perhaps?")
Jean-Paul Calderone9eadb962008-09-07 21:20:44 -0400256
257
258 def test_set_default_verify_paths_signature(self):
259 """
260 L{Context.set_default_verify_paths} takes no arguments and raises
261 L{TypeError} if given any.
262 """
263 context = Context(TLSv1_METHOD)
264 self.assertRaises(TypeError, context.set_default_verify_paths, None)
265 self.assertRaises(TypeError, context.set_default_verify_paths, 1)
266 self.assertRaises(TypeError, context.set_default_verify_paths, "")
Jean-Paul Calderone327d8f92008-12-28 21:55:56 -0500267
268
269
270class ConstantsTests(TestCase):
271 """
272 Tests for the values of constants exposed in L{OpenSSL.SSL}.
273
274 These are values defined by OpenSSL intended only to be used as flags to
275 OpenSSL APIs. The only assertions it seems can be made about them is
276 their values.
277 """
Jean-Paul Calderoned811b682008-12-28 22:59:15 -0500278 # unittest.TestCase has no skip mechanism
279 if OP_NO_QUERY_MTU is not None:
280 def test_op_no_query_mtu(self):
281 """
282 The value of L{OpenSSL.SSL.OP_NO_QUERY_MTU} is 0x1000, the value of
283 I{SSL_OP_NO_QUERY_MTU} defined by I{openssl/ssl.h}.
284 """
285 self.assertEqual(OP_NO_QUERY_MTU, 0x1000)
286 else:
287 "OP_NO_QUERY_MTU unavailable - OpenSSL version may be too old"
Jean-Paul Calderone327d8f92008-12-28 21:55:56 -0500288
289
Jean-Paul Calderoned811b682008-12-28 22:59:15 -0500290 if OP_COOKIE_EXCHANGE is not None:
291 def test_op_cookie_exchange(self):
292 """
293 The value of L{OpenSSL.SSL.OP_COOKIE_EXCHANGE} is 0x2000, the value
294 of I{SSL_OP_COOKIE_EXCHANGE} defined by I{openssl/ssl.h}.
295 """
296 self.assertEqual(OP_COOKIE_EXCHANGE, 0x2000)
297 else:
298 "OP_COOKIE_EXCHANGE unavailable - OpenSSL version may be too old"
Jean-Paul Calderone327d8f92008-12-28 21:55:56 -0500299
300
Jean-Paul Calderoned811b682008-12-28 22:59:15 -0500301 if OP_NO_TICKET is not None:
302 def test_op_no_ticket(self):
303 """
304 The value of L{OpenSSL.SSL.OP_NO_TICKET} is 0x4000, the value of
305 I{SSL_OP_NO_TICKET} defined by I{openssl/ssl.h}.
306 """
307 self.assertEqual(OP_NO_TICKET, 0x4000)
308 else:
309 "OP_NO_TICKET unavailable - OpenSSL version may be too old"
Rick Dean5b7b6372009-04-01 11:34:06 -0500310
311
Jean-Paul Calderoneeeee26a2009-04-27 11:24:30 -0400312
Rick Deanb71c0d22009-04-01 14:09:23 -0500313root_cert_pem = """-----BEGIN CERTIFICATE-----
314MIIC7TCCAlagAwIBAgIIPQzE4MbeufQwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UE
315BhMCVVMxCzAJBgNVBAgTAklMMRAwDgYDVQQHEwdDaGljYWdvMRAwDgYDVQQKEwdU
316ZXN0aW5nMRgwFgYDVQQDEw9UZXN0aW5nIFJvb3QgQ0EwIhgPMjAwOTAzMjUxMjM2
317NThaGA8yMDE3MDYxMTEyMzY1OFowWDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAklM
318MRAwDgYDVQQHEwdDaGljYWdvMRAwDgYDVQQKEwdUZXN0aW5nMRgwFgYDVQQDEw9U
319ZXN0aW5nIFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPmaQumL
320urpE527uSEHdL1pqcDRmWzu+98Y6YHzT/J7KWEamyMCNZ6fRW1JCR782UQ8a07fy
3212xXsKy4WdKaxyG8CcatwmXvpvRQ44dSANMihHELpANTdyVp6DCysED6wkQFurHlF
3221dshEaJw8b/ypDhmbVIo6Ci1xvCJqivbLFnbAgMBAAGjgbswgbgwHQYDVR0OBBYE
323FINVdy1eIfFJDAkk51QJEo3IfgSuMIGIBgNVHSMEgYAwfoAUg1V3LV4h8UkMCSTn
324VAkSjch+BK6hXKRaMFgxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UE
325BxMHQ2hpY2FnbzEQMA4GA1UEChMHVGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBS
326b290IENBggg9DMTgxt659DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GB
327AGGCDazMJGoWNBpc03u6+smc95dEead2KlZXBATOdFT1VesY3+nUOqZhEhTGlDMi
328hkgaZnzoIq/Uamidegk4hirsCT/R+6vsKAAxNTcBjUeZjlykCJWy5ojShGftXIKY
329w/njVbKMXrvc83qmTdGl3TAM0fxQIpqgcglFLveEBgzn
330-----END CERTIFICATE-----
331"""
332
333root_key_pem = """-----BEGIN RSA PRIVATE KEY-----
334MIICXQIBAAKBgQD5mkLpi7q6ROdu7khB3S9aanA0Zls7vvfGOmB80/yeylhGpsjA
335jWen0VtSQke/NlEPGtO38tsV7CsuFnSmschvAnGrcJl76b0UOOHUgDTIoRxC6QDU
3363claegwsrBA+sJEBbqx5RdXbIRGicPG/8qQ4Zm1SKOgotcbwiaor2yxZ2wIDAQAB
337AoGBAPCgMpmLxzwDaUmcFbTJUvlLW1hoxNNYSu2jIZm1k/hRAcE60JYwvBkgz3UB
338yMEh0AtLxYe0bFk6EHah11tMUPgscbCq73snJ++8koUw+csk22G65hOs51bVb7Aa
3396JBe67oLzdtvgCUFAA2qfrKzWRZzAdhUirQUZgySZk+Xq1pBAkEA/kZG0A6roTSM
340BVnx7LnPfsycKUsTumorpXiylZJjTi9XtmzxhrYN6wgZlDOOwOLgSQhszGpxVoMD
341u3gByT1b2QJBAPtL3mSKdvwRu/+40zaZLwvSJRxaj0mcE4BJOS6Oqs/hS1xRlrNk
342PpQ7WJ4yM6ZOLnXzm2mKyxm50Mv64109FtMCQQDOqS2KkjHaLowTGVxwC0DijMfr
343I9Lf8sSQk32J5VWCySWf5gGTfEnpmUa41gKTMJIbqZZLucNuDcOtzUaeWZlZAkA8
344ttXigLnCqR486JDPTi9ZscoZkZ+w7y6e/hH8t6d5Vjt48JVyfjPIaJY+km58LcN3
3456AWSeGAdtRFHVzR7oHjVAkB4hutvxiOeiIVQNBhM6RSI9aBPMI21DoX2JRoxvNW2
346cbvAhow217X9V0dVerEOKxnNYspXRrh36h7k4mQA+sDq
347-----END RSA PRIVATE KEY-----
348"""
349
350server_cert_pem = """-----BEGIN CERTIFICATE-----
351MIICKDCCAZGgAwIBAgIJAJn/HpR21r/8MA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
352BAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEQMA4GA1UEChMH
353VGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBSb290IENBMCIYDzIwMDkwMzI1MTIz
354NzUzWhgPMjAxNzA2MTExMjM3NTNaMBgxFjAUBgNVBAMTDWxvdmVseSBzZXJ2ZXIw
355gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAL6m+G653V0tpBC/OKl22VxOi2Cv
356lK4TYu9LHSDP9uDVTe7V5D5Tl6qzFoRRx5pfmnkqT5B+W9byp2NU3FC5hLm5zSAr
357b45meUhjEJ/ifkZgbNUjHdBIGP9MAQUHZa5WKdkGIJvGAvs8UzUqlr4TBWQIB24+
358lJ+Ukk/CRgasrYwdAgMBAAGjNjA0MB0GA1UdDgQWBBS4kC7Ij0W1TZXZqXQFAM2e
359gKEG2DATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQUFAAOBgQBh30Li
360dJ+NlxIOx5343WqIBka3UbsOb2kxWrbkVCrvRapCMLCASO4FqiKWM+L0VDBprqIp
3612mgpFQ6FHpoIENGvJhdEKpptQ5i7KaGhnDNTfdy3x1+h852G99f1iyj0RmbuFcM8
362uzujnS8YXWvM7DM1Ilozk4MzPug8jzFp5uhKCQ==
363-----END CERTIFICATE-----
364"""
365
366server_key_pem = """-----BEGIN RSA PRIVATE KEY-----
367MIICWwIBAAKBgQC+pvhuud1dLaQQvzipdtlcTotgr5SuE2LvSx0gz/bg1U3u1eQ+
368U5eqsxaEUceaX5p5Kk+QflvW8qdjVNxQuYS5uc0gK2+OZnlIYxCf4n5GYGzVIx3Q
369SBj/TAEFB2WuVinZBiCbxgL7PFM1Kpa+EwVkCAduPpSflJJPwkYGrK2MHQIDAQAB
370AoGAbwuZ0AR6JveahBaczjfnSpiFHf+mve2UxoQdpyr6ROJ4zg/PLW5K/KXrC48G
371j6f3tXMrfKHcpEoZrQWUfYBRCUsGD5DCazEhD8zlxEHahIsqpwA0WWssJA2VOLEN
372j6DuV2pCFbw67rfTBkTSo32ahfXxEKev5KswZk0JIzH3ooECQQDgzS9AI89h0gs8
373Dt+1m11Rzqo3vZML7ZIyGApUzVan+a7hbc33nbGRkAXjHaUBJO31it/H6dTO+uwX
374msWwNG5ZAkEA2RyFKs5xR5USTFaKLWCgpH/ydV96KPOpBND7TKQx62snDenFNNbn
375FwwOhpahld+vqhYk+pfuWWUpQciE+Bu7ZQJASjfT4sQv4qbbKK/scePicnDdx9th
3764e1EeB9xwb+tXXXUo/6Bor/AcUNwfiQ6Zt9PZOK9sR3lMZSsP7rMi7kzuQJABie6
3771sXXjFH7nNJvRG4S39cIxq8YRYTy68II/dlB2QzGpKxV/POCxbJ/zu0CU79tuYK7
378NaeNCFfH3aeTrX0LyQJAMBWjWmeKM2G2sCExheeQK0ROnaBC8itCECD4Jsve4nqf
379r50+LF74iLXFwqysVCebPKMOpDWp/qQ1BbJQIPs7/A==
380-----END RSA PRIVATE KEY-----
381"""
382
383client_cert_pem = """-----BEGIN CERTIFICATE-----
384MIICJjCCAY+gAwIBAgIJAKxpFI5lODkjMA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
385BAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEQMA4GA1UEChMH
386VGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBSb290IENBMCIYDzIwMDkwMzI1MTIz
387ODA1WhgPMjAxNzA2MTExMjM4MDVaMBYxFDASBgNVBAMTC3VnbHkgY2xpZW50MIGf
388MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAZh/SRtNm5ntMT4qb6YzEpTroMlq2
389rn+GrRHRiZ+xkCw/CGNhbtPir7/QxaUj26BSmQrHw1bGKEbPsWiW7bdXSespl+xK
390iku4G/KvnnmWdeJHqsiXeUZtqurMELcPQAw9xPHEuhqqUJvvEoMTsnCEqGM+7Dtb
391oCRajYyHfluARQIDAQABozYwNDAdBgNVHQ4EFgQUNQB+qkaOaEVecf1J3TTUtAff
3920fAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADgYEAyv/Jh7gM
393Q3OHvmsFEEvRI+hsW8y66zK4K5de239Y44iZrFYkt7Q5nBPMEWDj4F2hLYWL/qtI
3949Zdr0U4UDCU9SmmGYh4o7R4TZ5pGFvBYvjhHbkSFYFQXZxKUi+WUxplP6I0wr2KJ
395PSTJCjJOn3xo2NTKRgV1gaoTf2EhL+RG8TQ=
396-----END CERTIFICATE-----
397"""
398
399client_key_pem = """-----BEGIN RSA PRIVATE KEY-----
400MIICXgIBAAKBgQDAZh/SRtNm5ntMT4qb6YzEpTroMlq2rn+GrRHRiZ+xkCw/CGNh
401btPir7/QxaUj26BSmQrHw1bGKEbPsWiW7bdXSespl+xKiku4G/KvnnmWdeJHqsiX
402eUZtqurMELcPQAw9xPHEuhqqUJvvEoMTsnCEqGM+7DtboCRajYyHfluARQIDAQAB
403AoGATkZ+NceY5Glqyl4mD06SdcKfV65814vg2EL7V9t8+/mi9rYL8KztSXGlQWPX
404zuHgtRoMl78yQ4ZJYOBVo+nsx8KZNRCEBlE19bamSbQLCeQMenWnpeYyQUZ908gF
405h6L9qsFVJepgA9RDgAjyDoS5CaWCdCCPCH2lDkdcqC54SVUCQQDseuduc4wi8h4t
406V8AahUn9fn9gYfhoNuM0gdguTA0nPLVWz4hy1yJiWYQe0H7NLNNTmCKiLQaJpAbb
407TC6vE8C7AkEA0Ee8CMJUc20BnGEmxwgWcVuqFWaKCo8jTH1X38FlATUsyR3krjW2
408dL3yDD9NwHxsYP7nTKp/U8MV7U9IBn4y/wJBAJl7H0/BcLeRmuJk7IqJ7b635iYB
409D/9beFUw3MUXmQXZUfyYz39xf6CDZsu1GEdEC5haykeln3Of4M9d/4Kj+FcCQQCY
410si6xwT7GzMDkk/ko684AV3KPc/h6G0yGtFIrMg7J3uExpR/VdH2KgwMkZXisSMvw
411JJEQjOMCVsEJlRk54WWjAkEAzoZNH6UhDdBK5F38rVt/y4SEHgbSfJHIAmPS32Kq
412f6GGcfNpip0Uk7q7udTKuX7Q/buZi/C4YW7u3VKAquv9NA==
413-----END RSA PRIVATE KEY-----
414"""
415
416def verify_cb(conn, cert, errnum, depth, ok):
417 return ok
418
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400419class MemoryBIOTests(TestCase):
Rick Deanb71c0d22009-04-01 14:09:23 -0500420 """
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400421 Tests for L{OpenSSL.SSL.Connection} using a memory BIO.
Rick Deanb71c0d22009-04-01 14:09:23 -0500422 """
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400423 def _server(self):
424 # Create the server side Connection. This is mostly setup boilerplate
425 # - use TLSv1, use a particular certificate, etc.
426 server_ctx = Context(TLSv1_METHOD)
427 server_ctx.set_options(OP_NO_SSLv2 | OP_NO_SSLv3 | OP_SINGLE_DH_USE )
428 server_ctx.set_verify(VERIFY_PEER|VERIFY_FAIL_IF_NO_PEER_CERT|VERIFY_CLIENT_ONCE, verify_cb)
429 server_store = server_ctx.get_cert_store()
430 server_ctx.use_privatekey(load_privatekey(FILETYPE_PEM, server_key_pem))
431 server_ctx.use_certificate(load_certificate(FILETYPE_PEM, server_cert_pem))
432 server_ctx.check_privatekey()
433 server_store.add_cert(load_certificate(FILETYPE_PEM, root_cert_pem))
434 # Here the Connection is actually created. None is passed as the 2nd
435 # parameter, indicating a memory BIO should be created.
436 server_conn = Connection(server_ctx, None)
437 server_conn.set_accept_state()
438 return server_conn
439
440
441 def _client(self):
442 # Now create the client side Connection. Similar boilerplate to the above.
443 client_ctx = Context(TLSv1_METHOD)
444 client_ctx.set_options(OP_NO_SSLv2 | OP_NO_SSLv3 | OP_SINGLE_DH_USE )
445 client_ctx.set_verify(VERIFY_PEER|VERIFY_FAIL_IF_NO_PEER_CERT|VERIFY_CLIENT_ONCE, verify_cb)
446 client_store = client_ctx.get_cert_store()
447 client_ctx.use_privatekey(load_privatekey(FILETYPE_PEM, client_key_pem))
448 client_ctx.use_certificate(load_certificate(FILETYPE_PEM, client_cert_pem))
449 client_ctx.check_privatekey()
450 client_store.add_cert(load_certificate(FILETYPE_PEM, root_cert_pem))
451 # Again, None to create a new memory BIO.
452 client_conn = Connection(client_ctx, None)
453 client_conn.set_connect_state()
454 return client_conn
455
456
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400457 def _loopback(self, client_conn, server_conn):
458 """
459 Try to read application bytes from each of the two L{Connection}
460 objects. Copy bytes back and forth between their send/receive buffers
461 for as long as there is anything to copy. When there is nothing more
462 to copy, return C{None}. If one of them actually manages to deliver
463 some application bytes, return a two-tuple of the connection from which
464 the bytes were read and the bytes themselves.
465 """
466 wrote = True
467 while wrote:
468 # Loop until neither side has anything to say
469 wrote = False
470
471 # Copy stuff from each side's send buffer to the other side's
472 # receive buffer.
473 for (read, write) in [(client_conn, server_conn),
474 (server_conn, client_conn)]:
475
476 # Give the side a chance to generate some more bytes, or
477 # succeed.
478 try:
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400479 bytes = read.recv(2 ** 16)
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400480 except WantReadError:
481 # It didn't succeed, so we'll hope it generated some
482 # output.
483 pass
484 else:
485 # It did succeed, so we'll stop now and let the caller deal
486 # with it.
487 return (read, bytes)
488
489 while True:
490 # Keep copying as long as there's more stuff there.
491 try:
492 dirty = read.bio_read(4096)
493 except WantReadError:
494 # Okay, nothing more waiting to be sent. Stop
495 # processing this send buffer.
496 break
497 else:
498 # Keep track of the fact that someone generated some
499 # output.
500 wrote = True
501 write.bio_write(dirty)
502
503
Rick Deanb71c0d22009-04-01 14:09:23 -0500504 def test_connect(self):
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400505 """
506 Two L{Connection}s which use memory BIOs can be manually connected by
507 reading from the output of each and writing those bytes to the input of
508 the other and in this way establish a connection and exchange
509 application-level bytes with each other.
510 """
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400511 server_conn = self._server()
512 client_conn = self._client()
Rick Deanb71c0d22009-04-01 14:09:23 -0500513
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400514 # There should be no key or nonces yet.
515 self.assertIdentical(server_conn.master_key(), None)
516 self.assertIdentical(server_conn.client_random(), None)
517 self.assertIdentical(server_conn.server_random(), None)
Rick Deanb71c0d22009-04-01 14:09:23 -0500518
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400519 # First, the handshake needs to happen. We'll deliver bytes back and
520 # forth between the client and server until neither of them feels like
521 # speaking any more.
522 self.assertIdentical(self._loopback(client_conn, server_conn), None)
523
524 # Now that the handshake is done, there should be a key and nonces.
525 self.assertNotIdentical(server_conn.master_key(), None)
526 self.assertNotIdentical(server_conn.client_random(), None)
527 self.assertNotIdentical(server_conn.server_random(), None)
528 self.assertNotIdentical(server_conn.client_random(), client_conn.client_random())
529 self.assertNotIdentical(server_conn.server_random(), client_conn.server_random())
530
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
Jean-Paul Calderonefc4ed0f2009-04-27 11:51:27 -0400545 def test_socketOverridesMemory(self):
Rick Deanb71c0d22009-04-01 14:09:23 -0500546 """
547 Test that L{OpenSSL.SSL.bio_read} and L{OpenSSL.SSL.bio_write} don't
548 work on L{OpenSSL.SSL.Connection}() that use sockets.
549 """
550 context = Context(SSLv3_METHOD)
551 client = socket()
552 clientSSL = Connection(context, client)
553 self.assertRaises( TypeError, clientSSL.bio_read, 100)
554 self.assertRaises( TypeError, clientSSL.bio_write, "foo")
Jean-Paul Calderone07acf3f2009-05-05 13:23:28 -0400555 self.assertRaises( TypeError, clientSSL.bio_shutdown )
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400556
557
558 def test_outgoingOverflow(self):
559 """
560 If more bytes than can be written to the memory BIO are passed to
561 L{Connection.send} at once, the number of bytes which were written is
562 returned and that many bytes from the beginning of the input can be
563 read from the other end of the connection.
564 """
565 server = self._server()
566 client = self._client()
567
568 self._loopback(client, server)
569
570 size = 2 ** 15
571 sent = client.send("x" * size)
572 # Sanity check. We're trying to test what happens when the entire
573 # input can't be sent. If the entire input was sent, this test is
574 # meaningless.
575 self.assertTrue(sent < size)
576
577 receiver, received = self._loopback(client, server)
578 self.assertIdentical(receiver, server)
579
580 # We can rely on all of these bytes being received at once because
581 # _loopback passes 2 ** 16 to recv - more than 2 ** 15.
582 self.assertEquals(len(received), sent)
Jean-Paul Calderone3ad85d42009-04-30 20:24:35 -0400583
584
585 def test_shutdown(self):
586 """
587 L{Connection.bio_shutdown} signals the end of the data stream from
588 which the L{Connection} reads.
589 """
590 server = self._server()
591 server.bio_shutdown()
592 e = self.assertRaises(Error, server.recv, 1024)
593 # We don't want WantReadError or ZeroReturnError or anything - it's a
594 # handshake failure.
595 self.assertEquals(e.__class__, Error)
Jean-Paul Calderone0b88b6a2009-07-05 12:44:41 -0400596
597
598
599if __name__ == '__main__':
600 main()