blob: 2aa265ae307157a3e4febf51831c2d18c8d22152 [file] [log] [blame]
Thomas Woutersed03b412007-08-28 21:37:11 +00001# Test the support for SSL and sockets
2
3import sys
4import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00005from test import support
Thomas Woutersed03b412007-08-28 21:37:11 +00006import socket
Bill Janssen6e027db2007-11-15 22:23:56 +00007import select
Thomas Woutersed03b412007-08-28 21:37:11 +00008import time
9import os
10import pprint
Jeremy Hylton1afc1692008-06-18 20:49:58 +000011import urllib.parse, urllib.request
Thomas Woutersed03b412007-08-28 21:37:11 +000012import traceback
Bill Janssen54cc54c2007-12-14 22:08:56 +000013import asyncore
Thomas Woutersed03b412007-08-28 21:37:11 +000014
Georg Brandl24420152008-05-26 16:32:26 +000015from http.server import HTTPServer, SimpleHTTPRequestHandler
Thomas Wouters1b7f8912007-09-19 03:06:30 +000016
Thomas Woutersed03b412007-08-28 21:37:11 +000017# Optionally test SSL support, if we have it in the tested platform
18skip_expected = False
19try:
20 import ssl
21except ImportError:
22 skip_expected = True
23
Benjamin Petersonee8712c2008-05-20 21:35:26 +000024HOST = support.HOST
Thomas Woutersed03b412007-08-28 21:37:11 +000025CERTFILE = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +000026SVN_PYTHON_ORG_ROOT_CERT = None
Thomas Woutersed03b412007-08-28 21:37:11 +000027
Thomas Woutersed03b412007-08-28 21:37:11 +000028def handle_error(prefix):
29 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +000030 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000031 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +000032
33
34class BasicTests(unittest.TestCase):
35
Georg Brandlfceab5a2008-01-19 20:08:23 +000036 def testSSLconnect(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000037 if not support.is_resource_enabled('network'):
Georg Brandlfceab5a2008-01-19 20:08:23 +000038 return
39 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
40 cert_reqs=ssl.CERT_NONE)
41 s.connect(("svn.python.org", 443))
42 c = s.getpeercert()
43 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +000044 raise support.TestFailed("Peer cert %s shouldn't be here!")
Georg Brandlfceab5a2008-01-19 20:08:23 +000045 s.close()
46
47 # this should fail because we have no verification certs
48 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
49 cert_reqs=ssl.CERT_REQUIRED)
50 try:
51 s.connect(("svn.python.org", 443))
52 except ssl.SSLError:
53 pass
54 finally:
55 s.close()
56
Thomas Wouters1b7f8912007-09-19 03:06:30 +000057 def testCrucialConstants(self):
58 ssl.PROTOCOL_SSLv2
59 ssl.PROTOCOL_SSLv23
60 ssl.PROTOCOL_SSLv3
61 ssl.PROTOCOL_TLSv1
62 ssl.CERT_NONE
63 ssl.CERT_OPTIONAL
64 ssl.CERT_REQUIRED
Thomas Woutersed03b412007-08-28 21:37:11 +000065
Thomas Wouters1b7f8912007-09-19 03:06:30 +000066 def testRAND(self):
67 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +000068 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000069 sys.stdout.write("\n RAND_status is %d (%s)\n"
70 % (v, (v and "sufficient randomness") or
71 "insufficient randomness"))
Thomas Woutersed03b412007-08-28 21:37:11 +000072 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000073 ssl.RAND_egd(1)
74 except TypeError:
75 pass
Thomas Woutersed03b412007-08-28 21:37:11 +000076 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000077 print("didn't raise TypeError")
78 ssl.RAND_add("this is a random string", 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +000079
Thomas Wouters1b7f8912007-09-19 03:06:30 +000080 def testParseCert(self):
81 # note that this uses an 'unofficial' function in _ssl.c,
82 # provided solely for this test, to exercise the certificate
83 # parsing code
84 p = ssl._ssl._test_decode_cert(CERTFILE, False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +000085 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000086 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
Thomas Woutersed03b412007-08-28 21:37:11 +000087
Thomas Wouters1b7f8912007-09-19 03:06:30 +000088 def testDERtoPEM(self):
89
90 pem = open(SVN_PYTHON_ORG_ROOT_CERT, 'r').read()
91 d1 = ssl.PEM_cert_to_DER_cert(pem)
92 p2 = ssl.DER_cert_to_PEM_cert(d1)
93 d2 = ssl.PEM_cert_to_DER_cert(p2)
94 if (d1 != d2):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000095 raise support.TestFailed("PEM-to-DER or DER-to-PEM translation failed")
Thomas Wouters1b7f8912007-09-19 03:06:30 +000096
Antoine Pitrou04f6a322010-04-05 21:40:07 +000097 def test_openssl_version(self):
98 n = ssl.OPENSSL_VERSION_NUMBER
99 t = ssl.OPENSSL_VERSION_INFO
100 s = ssl.OPENSSL_VERSION
101 self.assertIsInstance(n, int)
102 self.assertIsInstance(t, tuple)
103 self.assertIsInstance(s, str)
104 # Some sanity checks follow
105 # >= 0.9
106 self.assertGreaterEqual(n, 0x900000)
107 # < 2.0
108 self.assertLess(n, 0x20000000)
109 major, minor, fix, patch, status = t
110 self.assertGreaterEqual(major, 0)
111 self.assertLess(major, 2)
112 self.assertGreaterEqual(minor, 0)
113 self.assertLess(minor, 256)
114 self.assertGreaterEqual(fix, 0)
115 self.assertLess(fix, 256)
116 self.assertGreaterEqual(patch, 0)
117 self.assertLessEqual(patch, 26)
118 self.assertGreaterEqual(status, 0)
119 self.assertLessEqual(status, 15)
120 # Version string as returned by OpenSSL, the format might change
121 self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)),
122 (s, t))
123
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000124 def test_ciphers(self):
125 if not support.is_resource_enabled('network'):
126 return
127 remote = ("svn.python.org", 443)
128 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
129 cert_reqs=ssl.CERT_NONE, ciphers="ALL")
130 s.connect(remote)
131 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
132 cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT")
133 s.connect(remote)
134 # Error checking occurs when connecting, because the SSL context
135 # isn't created before.
136 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
137 cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
138 with self.assertRaisesRegexp(ssl.SSLError, "No cipher can be selected"):
139 s.connect(remote)
140
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000141
Bill Janssen6e027db2007-11-15 22:23:56 +0000142class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000143
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000144 def testConnect(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000145 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
146 cert_reqs=ssl.CERT_NONE)
147 s.connect(("svn.python.org", 443))
148 c = s.getpeercert()
149 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000150 raise support.TestFailed("Peer cert %s shouldn't be here!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000151 s.close()
152
153 # this should fail because we have no verification certs
154 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
155 cert_reqs=ssl.CERT_REQUIRED)
Thomas Woutersed03b412007-08-28 21:37:11 +0000156 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000157 s.connect(("svn.python.org", 443))
158 except ssl.SSLError:
159 pass
160 finally:
161 s.close()
162
163 # this should succeed because we specify the root cert
164 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
165 cert_reqs=ssl.CERT_REQUIRED,
166 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
167 try:
168 s.connect(("svn.python.org", 443))
169 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000170 raise support.TestFailed("Unexpected exception %s" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000171 finally:
172 s.close()
173
Bill Janssen6e027db2007-11-15 22:23:56 +0000174 def testNonBlockingHandshake(self):
175 s = socket.socket(socket.AF_INET)
176 s.connect(("svn.python.org", 443))
177 s.setblocking(False)
178 s = ssl.wrap_socket(s,
179 cert_reqs=ssl.CERT_NONE,
180 do_handshake_on_connect=False)
181 count = 0
182 while True:
183 try:
184 count += 1
185 s.do_handshake()
186 break
187 except ssl.SSLError as err:
188 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
189 select.select([s], [], [])
190 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
191 select.select([], [s], [])
192 else:
193 raise
194 s.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000195 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000196 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000197
Bill Janssen54cc54c2007-12-14 22:08:56 +0000198 def testFetchServerCert(self):
199
200 pem = ssl.get_server_certificate(("svn.python.org", 443))
201 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000202 raise support.TestFailed("No server certificate on svn.python.org:443!")
Bill Janssen54cc54c2007-12-14 22:08:56 +0000203
204 return
205
206 try:
207 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
208 except ssl.SSLError as x:
209 #should fail
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000210 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000211 sys.stdout.write("%s\n" % x)
212 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000213 raise support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000214
215 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
216 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000217 raise support.TestFailed("No server certificate on svn.python.org:443!")
218 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000219 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
220
Antoine Pitroufec12ff2010-04-21 19:46:23 +0000221 def test_algorithms(self):
222 # Issue #8484: all algorithms should be available when verifying a
223 # certificate.
Antoine Pitrou29619b22010-04-22 18:43:31 +0000224 # SHA256 was added in OpenSSL 0.9.8
225 if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
226 self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
Antoine Pitroufec12ff2010-04-21 19:46:23 +0000227 # NOTE: https://sha256.tbs-internet.com is another possible test host
228 remote = ("sha2.hboeck.de", 443)
229 sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
230 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
231 cert_reqs=ssl.CERT_REQUIRED,
232 ca_certs=sha256_cert,)
233 with support.transient_internet():
234 try:
235 s.connect(remote)
236 if support.verbose:
237 sys.stdout.write("\nCipher with %r is %r\n" %
238 (remote, s.cipher()))
239 sys.stdout.write("Certificate is:\n%s\n" %
240 pprint.pformat(s.getpeercert()))
241 finally:
242 s.close()
243
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000244
245try:
246 import threading
247except ImportError:
248 _have_threads = False
249else:
250
251 _have_threads = True
252
253 class ThreadedEchoServer(threading.Thread):
254
255 class ConnectionHandler(threading.Thread):
256
257 """A mildly complicated class, because we want it to work both
258 with and without the SSL wrapper around the socket connection, so
259 that we can test the STARTTLS functionality."""
260
Bill Janssen6e027db2007-11-15 22:23:56 +0000261 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000262 self.server = server
263 self.running = False
264 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000265 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000266 self.sock.setblocking(1)
267 self.sslconn = None
268 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000269 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000270
271 def wrap_conn (self):
272 try:
273 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
274 certfile=self.server.certificate,
275 ssl_version=self.server.protocol,
276 ca_certs=self.server.cacerts,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000277 cert_reqs=self.server.certreqs,
278 ciphers=self.server.ciphers)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000279 except:
280 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000281 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000282 if not self.server.expect_bad_connects:
283 # here, we want to stop the server, because this shouldn't
284 # happen in the context of our test case
285 self.running = False
286 # normally, we'd just stop here, but for the test
287 # harness, we want to stop the server
288 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000289 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000290 return False
291
292 else:
293 if self.server.certreqs == ssl.CERT_REQUIRED:
294 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000295 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000296 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
297 cert_binary = self.sslconn.getpeercert(True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000298 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000299 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
300 cipher = self.sslconn.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000301 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000302 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
303 return True
304
305 def read(self):
306 if self.sslconn:
307 return self.sslconn.read()
308 else:
309 return self.sock.recv(1024)
310
311 def write(self, bytes):
312 if self.sslconn:
313 return self.sslconn.write(bytes)
314 else:
315 return self.sock.send(bytes)
316
317 def close(self):
318 if self.sslconn:
319 self.sslconn.close()
320 else:
321 self.sock.close()
322
323 def run (self):
324 self.running = True
325 if not self.server.starttls_server:
326 if not self.wrap_conn():
327 return
328 while self.running:
329 try:
330 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000331 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000332 if not msg:
333 # eof, so quit this handler
334 self.running = False
335 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000336 elif amsg.strip() == 'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000337 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000338 sys.stdout.write(" server: client closed connection\n")
339 self.close()
340 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000341 elif (self.server.starttls_server and
342 amsg.strip() == 'STARTTLS'):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000343 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000344 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000345 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000346 if not self.wrap_conn():
347 return
Bill Janssen40a0f662008-08-12 16:56:25 +0000348 elif (self.server.starttls_server and self.sslconn
349 and amsg.strip() == 'ENDTLS'):
350 if support.verbose and self.server.connectionchatty:
351 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
352 self.write("OK\n".encode("ASCII", "strict"))
353 self.sock = self.sslconn.unwrap()
354 self.sslconn = None
355 if support.verbose and self.server.connectionchatty:
356 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000357 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000358 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000359 self.server.connectionchatty):
360 ctype = (self.sslconn and "encrypted") or "unencrypted"
361 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
362 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000363 self.write(amsg.lower().encode('ASCII', 'strict'))
364 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000365 if self.server.chatty:
366 handle_error("Test server failure:\n")
367 self.close()
368 self.running = False
369 # normally, we'd just stop here, but for the test
370 # harness, we want to stop the server
371 self.server.stop()
372 except:
373 handle_error('')
374
Trent Nelson78520002008-04-10 20:54:35 +0000375 def __init__(self, certificate, ssl_version=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000376 certreqs=None, cacerts=None, expect_bad_connects=False,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000377 chatty=True, connectionchatty=False, starttls_server=False,
378 ciphers=None):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000379 if ssl_version is None:
380 ssl_version = ssl.PROTOCOL_TLSv1
381 if certreqs is None:
382 certreqs = ssl.CERT_NONE
383 self.certificate = certificate
384 self.protocol = ssl_version
385 self.certreqs = certreqs
386 self.cacerts = cacerts
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000387 self.ciphers = ciphers
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000388 self.expect_bad_connects = expect_bad_connects
389 self.chatty = chatty
390 self.connectionchatty = connectionchatty
391 self.starttls_server = starttls_server
392 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000393 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000394 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000395 self.active = False
396 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000397 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000398
399 def start (self, flag=None):
400 self.flag = flag
401 threading.Thread.start(self)
402
403 def run (self):
404 self.sock.settimeout(0.5)
405 self.sock.listen(5)
406 self.active = True
407 if self.flag:
408 # signal an event
409 self.flag.set()
410 while self.active:
411 try:
412 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000413 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000414 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000415 + repr(connaddr) + '\n')
416 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000417 handler.start()
418 except socket.timeout:
419 pass
420 except KeyboardInterrupt:
421 self.stop()
422 except:
423 if self.chatty:
424 handle_error("Test server failure:\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000425 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000426
427 def stop (self):
428 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000429
Bill Janssen54cc54c2007-12-14 22:08:56 +0000430 class OurHTTPSServer(threading.Thread):
431
432 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000433
434 class HTTPSServer(HTTPServer):
435
436 def __init__(self, server_address, RequestHandlerClass, certfile):
437
438 HTTPServer.__init__(self, server_address, RequestHandlerClass)
439 # we assume the certfile contains both private key and certificate
440 self.certfile = certfile
441 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000442 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000443 self.allow_reuse_address = True
444
Bill Janssen6e027db2007-11-15 22:23:56 +0000445 def __str__(self):
446 return ('<%s %s:%s>' %
447 (self.__class__.__name__,
448 self.server_name,
449 self.server_port))
450
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000451 def get_request (self):
452 # override this to wrap socket with SSL
453 sock, addr = self.socket.accept()
454 sslconn = ssl.wrap_socket(sock, server_side=True,
455 certfile=self.certfile)
456 return sslconn, addr
457
458 # The methods overridden below this are mainly so that we
459 # can run it in a thread and be able to stop it from another
460 # You probably wouldn't need them in other uses.
461
462 def server_activate(self):
463 # We want to run this in a thread for testing purposes,
464 # so we override this to set timeout, so that we get
465 # a chance to stop the server
466 self.socket.settimeout(0.5)
467 HTTPServer.server_activate(self)
468
469 def serve_forever(self):
470 # We want this to run in a thread, so we use a slightly
471 # modified version of "forever".
472 self.active = True
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000473 while 1:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000474 try:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000475 # We need to lock while handling the request.
476 # Another thread can close the socket after self.active
477 # has been checked and before the request is handled.
478 # This causes an exception when using the closed socket.
479 with self.active_lock:
480 if not self.active:
481 break
482 self.handle_request()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000483 except socket.timeout:
484 pass
485 except KeyboardInterrupt:
486 self.server_close()
487 return
488 except:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000489 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
490 break
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000491 time.sleep(0.1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000492
493 def server_close(self):
494 # Again, we want this to run in a thread, so we need to override
495 # close to clear the "active" flag, so that serve_forever() will
496 # terminate.
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000497 with self.active_lock:
498 HTTPServer.server_close(self)
499 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000500
501 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
502
503 # need to override translate_path to get a known root,
504 # instead of using os.curdir, since the test could be
505 # run from anywhere
506
507 server_version = "TestHTTPS/1.0"
508
509 root = None
510
511 def translate_path(self, path):
512 """Translate a /-separated PATH to the local filename syntax.
513
514 Components that mean special things to the local file system
515 (e.g. drive or directory names) are ignored. (XXX They should
516 probably be diagnosed.)
517
518 """
519 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000520 path = urllib.parse.urlparse(path)[2]
521 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000522 words = path.split('/')
523 words = filter(None, words)
524 path = self.root
525 for word in words:
526 drive, word = os.path.splitdrive(word)
527 head, word = os.path.split(word)
528 if word in self.root: continue
529 path = os.path.join(path, word)
530 return path
531
532 def log_message(self, format, *args):
533
534 # we override this to suppress logging unless "verbose"
535
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000536 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000537 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
538 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000539 self.server.server_port,
540 self.request.cipher(),
541 self.log_date_time_string(),
542 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000543
544
Trent Nelson78520002008-04-10 20:54:35 +0000545 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000546 self.flag = None
547 self.active = False
548 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000549 self.port = support.find_unused_port()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000550 self.server = self.HTTPSServer(
Trent Nelson78520002008-04-10 20:54:35 +0000551 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Thomas Woutersed03b412007-08-28 21:37:11 +0000552 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000553 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000554
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000555 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000556 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000557
558 def start (self, flag=None):
559 self.flag = flag
560 threading.Thread.start(self)
561
Thomas Woutersed03b412007-08-28 21:37:11 +0000562 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000563 self.active = True
564 if self.flag:
565 self.flag.set()
566 self.server.serve_forever()
567 self.active = False
568
569 def stop (self):
570 self.active = False
571 self.server.server_close()
572
573
Bill Janssen54cc54c2007-12-14 22:08:56 +0000574 class AsyncoreEchoServer(threading.Thread):
575
576 # this one's based on asyncore.dispatcher
577
578 class EchoServer (asyncore.dispatcher):
579
580 class ConnectionHandler (asyncore.dispatcher_with_send):
581
582 def __init__(self, conn, certfile):
583 self.socket = ssl.wrap_socket(conn, server_side=True,
584 certfile=certfile,
585 do_handshake_on_connect=False)
586 asyncore.dispatcher_with_send.__init__(self, self.socket)
587 # now we have to do the handshake
588 # we'll just do it the easy way, and block the connection
589 # till it's finished. If we were doing it right, we'd
590 # do this in multiple calls to handle_read...
591 self.do_handshake(block=True)
592
593 def readable(self):
594 if isinstance(self.socket, ssl.SSLSocket):
595 while self.socket.pending() > 0:
596 self.handle_read_event()
597 return True
598
599 def handle_read(self):
600 data = self.recv(1024)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000601 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000602 sys.stdout.write(" server: read %s from client\n" % repr(data))
603 if not data:
604 self.close()
605 else:
606 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
607
608 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000609 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000610 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000611 sys.stdout.write(" server: closed connection %s\n" % self.socket)
612
613 def handle_error(self):
614 raise
615
616 def __init__(self, port, certfile):
617 self.port = port
618 self.certfile = certfile
619 asyncore.dispatcher.__init__(self)
620 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
621 self.bind(('', port))
622 self.listen(5)
623
624 def handle_accept(self):
625 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000626 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000627 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
628 self.ConnectionHandler(sock_obj, self.certfile)
629
630 def handle_error(self):
631 raise
632
Trent Nelson78520002008-04-10 20:54:35 +0000633 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000634 self.flag = None
635 self.active = False
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000636 self.port = support.find_unused_port()
Trent Nelson78520002008-04-10 20:54:35 +0000637 self.server = self.EchoServer(self.port, certfile)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000638 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000639 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000640
641 def __str__(self):
642 return "<%s %s>" % (self.__class__.__name__, self.server)
643
644 def start (self, flag=None):
645 self.flag = flag
646 threading.Thread.start(self)
647
648 def run (self):
649 self.active = True
650 if self.flag:
651 self.flag.set()
652 while self.active:
653 try:
654 asyncore.loop(1)
655 except:
656 pass
657
658 def stop (self):
659 self.active = False
660 self.server.close()
661
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000662 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000663 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000664 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000665 cacerts=CERTFILE, chatty=False,
666 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000667 flag = threading.Event()
668 server.start(flag)
669 # wait for it to start
670 flag.wait()
671 # try to connect
672 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000673 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000674 s = ssl.wrap_socket(socket.socket(),
675 certfile=certfile,
676 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000677 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000678 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000679 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000680 sys.stdout.write("\nSSLError is %s\n" % x)
Bill Janssenddc56692008-07-17 18:17:20 +0000681 except socket.error as x:
682 if support.verbose:
683 sys.stdout.write("\nsocket.error is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000684 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000685 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000686 "Use of invalid cert should have failed!")
687 finally:
688 server.stop()
689 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000690
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000691 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000692 client_certfile, client_protocol=None,
693 indata="FOO\n",
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000694 ciphers=None, chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000695
Trent Nelson78520002008-04-10 20:54:35 +0000696 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000697 certreqs=certreqs,
698 ssl_version=protocol,
699 cacerts=cacertsfile,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000700 ciphers=ciphers,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000701 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000702 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000703 flag = threading.Event()
704 server.start(flag)
705 # wait for it to start
706 flag.wait()
707 # try to connect
708 if client_protocol is None:
709 client_protocol = protocol
710 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000711 s = ssl.wrap_socket(socket.socket(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000712 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000713 certfile=client_certfile,
714 ca_certs=cacertsfile,
715 cert_reqs=certreqs,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000716 ciphers=ciphers,
Bill Janssen6e027db2007-11-15 22:23:56 +0000717 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000718 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000719 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000720 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000721 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000722 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000723 else:
Antoine Pitrou7d7aede2009-11-25 18:55:32 +0000724 bindata = indata.encode('ASCII', 'strict')
725 for arg in [bindata, bytearray(bindata), memoryview(bindata)]:
726 if connectionchatty:
727 if support.verbose:
728 sys.stdout.write(
729 " client: sending %s...\n" % (repr(indata)))
730 s.write(arg)
731 outdata = s.read()
732 if connectionchatty:
733 if support.verbose:
734 sys.stdout.write(" client: read %s\n" % repr(outdata))
735 outdata = str(outdata, 'ASCII', 'strict')
736 if outdata != indata.lower():
737 raise support.TestFailed(
738 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
739 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
740 repr(indata[:min(len(indata),20)].lower()), len(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000741 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000742 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000743 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000744 sys.stdout.write(" client: closing connection.\n")
745 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000746 finally:
747 server.stop()
748 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000749
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000750 def tryProtocolCombo (server_protocol,
751 client_protocol,
752 expectedToWork,
753 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000754
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000755 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000756 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000757
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000758 if certsreqs == ssl.CERT_NONE:
759 certtype = "CERT_NONE"
760 elif certsreqs == ssl.CERT_OPTIONAL:
761 certtype = "CERT_OPTIONAL"
762 elif certsreqs == ssl.CERT_REQUIRED:
763 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000764 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000765 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
766 sys.stdout.write(formatstr %
767 (ssl.get_protocol_name(client_protocol),
768 ssl.get_protocol_name(server_protocol),
769 certtype))
770 try:
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000771 # NOTE: we must enable "ALL" ciphers, otherwise an SSLv23 client
772 # will send an SSLv3 hello (rather than SSLv2) starting from
773 # OpenSSL 1.0.0 (see issue #8322).
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000774 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000775 CERTFILE, CERTFILE, client_protocol,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000776 ciphers="ALL",
Bill Janssen6e027db2007-11-15 22:23:56 +0000777 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000778 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000779 if expectedToWork:
780 raise
781 else:
782 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000783 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000784 "Client protocol %s succeeded with server protocol %s!"
785 % (ssl.get_protocol_name(client_protocol),
786 ssl.get_protocol_name(server_protocol)))
787
788
Bill Janssen6e027db2007-11-15 22:23:56 +0000789 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000790
Trent Nelson6b240cd2008-04-10 20:12:06 +0000791 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000792
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000793 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000794 sys.stdout.write("\n")
795 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
796 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
797 chatty=True, connectionchatty=True)
798
799 def testReadCert(self):
800
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000801 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000802 sys.stdout.write("\n")
803 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000804 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000805 certreqs=ssl.CERT_NONE,
806 ssl_version=ssl.PROTOCOL_SSLv23,
807 cacerts=CERTFILE,
808 chatty=False)
809 flag = threading.Event()
810 server.start(flag)
811 # wait for it to start
812 flag.wait()
813 # try to connect
814 try:
815 try:
816 s = ssl.wrap_socket(socket.socket(),
817 certfile=CERTFILE,
818 ca_certs=CERTFILE,
819 cert_reqs=ssl.CERT_REQUIRED,
820 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000821 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000822 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000823 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000824 "Unexpected SSL error: " + str(x))
825 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000826 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000827 "Unexpected exception: " + str(x))
828 else:
829 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000830 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000831 "Can't SSL-handshake with test server")
832 cert = s.getpeercert()
833 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000834 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000835 "Can't get peer certificate.")
836 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000837 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000838 sys.stdout.write(pprint.pformat(cert) + '\n')
839 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000840 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000841 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000842 "No subject field in certificate: %s." %
843 pprint.pformat(cert))
844 if ((('organizationName', 'Python Software Foundation'),)
845 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000846 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000847 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000848 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000849 s.close()
850 finally:
851 server.stop()
852 server.join()
853
854 def testNULLcert(self):
855 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
856 "nullcert.pem"))
857 def testMalformedCert(self):
858 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
859 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000860 def testWrongCert(self):
861 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
862 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000863 def testMalformedKey(self):
864 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
865 "badkey.pem"))
866
Trent Nelson6b240cd2008-04-10 20:12:06 +0000867 def testRudeShutdown(self):
868
869 listener_ready = threading.Event()
870 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000871 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000872
873 # `listener` runs in a thread. It opens a socket listening on
874 # PORT, and sits in an accept() until the main thread connects.
875 # Then it rudely closes the socket, and sets Event `listener_gone`
876 # to let the main thread know the socket is gone.
877 def listener():
878 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000879 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000880 s.listen(5)
881 listener_ready.set()
882 s.accept()
883 s = None # reclaim the socket object, which also closes it
884 listener_gone.set()
885
886 def connector():
887 listener_ready.wait()
888 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000889 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000890 listener_gone.wait()
891 try:
892 ssl_sock = ssl.wrap_socket(s)
893 except IOError:
894 pass
895 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000896 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000897 'connecting to closed SSL socket should have failed')
898
899 t = threading.Thread(target=listener)
900 t.start()
901 connector()
902 t.join()
903
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000904 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000905 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000906 sys.stdout.write("\n")
907 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
908 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
909 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
910 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
911 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
912 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
913
914 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000915 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000916 sys.stdout.write("\n")
917 try:
918 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000919 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000920 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000921 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000922 sys.stdout.write(
923 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
924 % str(x))
925 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
926 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
927 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
928
929 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
930 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
931 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
932
933 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
934 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
935 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
936
937 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000938 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000939 sys.stdout.write("\n")
940 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
941 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
942 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
943 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
944 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
945 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
946
947 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000948 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000949 sys.stdout.write("\n")
950 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
951 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
952 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
953 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
954 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
955 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
956
957 def testSTARTTLS (self):
958
Bill Janssen40a0f662008-08-12 16:56:25 +0000959 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000960
Trent Nelson78520002008-04-10 20:54:35 +0000961 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000962 ssl_version=ssl.PROTOCOL_TLSv1,
963 starttls_server=True,
964 chatty=True,
965 connectionchatty=True)
966 flag = threading.Event()
967 server.start(flag)
968 # wait for it to start
969 flag.wait()
970 # try to connect
971 wrapped = False
972 try:
973 try:
974 s = socket.socket()
975 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000976 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000977 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000978 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000979 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000980 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000981 sys.stdout.write("\n")
982 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000983 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000984 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000985 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000986 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000987 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000988 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000989 outdata = conn.read()
990 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000991 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000992 outdata = s.recv(1024)
993 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000994 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000995 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000996 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000997 sys.stdout.write(
998 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000999 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001000 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001001 wrapped = True
Bill Janssen40a0f662008-08-12 16:56:25 +00001002 elif (indata == "ENDTLS" and
1003 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
1004 if support.verbose:
1005 msg = str(outdata, 'ASCII', 'replace')
1006 sys.stdout.write(
1007 " client: read %s from server, ending TLS...\n"
1008 % repr(msg))
1009 s = conn.unwrap()
1010 wrapped = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001011 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001012 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +00001013 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001014 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +00001015 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001016 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001017 sys.stdout.write(" client: closing connection.\n")
1018 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +00001019 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001020 else:
Bill Janssen40a0f662008-08-12 16:56:25 +00001021 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +00001022 if wrapped:
1023 conn.close()
1024 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001025 s.close()
1026 finally:
1027 server.stop()
1028 server.join()
1029
Bill Janssen54cc54c2007-12-14 22:08:56 +00001030 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +00001031
Trent Nelson78520002008-04-10 20:54:35 +00001032 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001033 flag = threading.Event()
1034 server.start(flag)
1035 # wait for it to start
1036 flag.wait()
1037 # try to connect
1038 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001039 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001040 sys.stdout.write('\n')
1041 d1 = open(CERTFILE, 'rb').read()
1042 d2 = ''
1043 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +00001044 url = 'https://%s:%d/%s' % (
1045 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001046 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +00001047 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001048 if dlen and (int(dlen) > 0):
1049 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001050 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001051 sys.stdout.write(
1052 " client: read %d bytes from remote server '%s'\n"
1053 % (len(d2), server))
1054 f.close()
1055 except:
1056 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001057 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001058 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001059 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001060 else:
1061 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +00001062 print("d1 is", len(d1), repr(d1))
1063 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001064 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001065 "Couldn't fetch data from HTTPS server")
1066 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001067 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001068 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001069 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001070 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001071 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001072 server.join()
1073
Trent Nelson6b240cd2008-04-10 20:12:06 +00001074 def testAsyncoreServer(self):
1075
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001076 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001077 sys.stdout.write("\n")
1078
1079 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001080 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001081 flag = threading.Event()
1082 server.start(flag)
1083 # wait for it to start
1084 flag.wait()
1085 # try to connect
1086 try:
1087 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +00001088 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001089 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001090 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001091 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001092 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001093 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001094 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001095 sys.stdout.write(
1096 " client: sending %s...\n" % (repr(indata)))
1097 s.sendall(indata.encode('ASCII', 'strict'))
1098 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001099 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001100 sys.stdout.write(" client: read %s\n" % repr(outdata))
1101 outdata = str(outdata, 'ASCII', 'strict')
1102 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001103 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001104 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1105 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1106 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1107 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001108 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001109 sys.stdout.write(" client: closing connection.\n")
1110 s.close()
1111 finally:
1112 server.stop()
1113 server.join()
1114
Bill Janssen58afe4c2008-09-08 16:45:19 +00001115 def testAllRecvAndSendMethods(self):
1116
1117 if support.verbose:
1118 sys.stdout.write("\n")
1119
1120 server = ThreadedEchoServer(CERTFILE,
1121 certreqs=ssl.CERT_NONE,
1122 ssl_version=ssl.PROTOCOL_TLSv1,
1123 cacerts=CERTFILE,
1124 chatty=True,
1125 connectionchatty=False)
1126 flag = threading.Event()
1127 server.start(flag)
1128 # wait for it to start
1129 flag.wait()
1130 # try to connect
1131 try:
1132 s = ssl.wrap_socket(socket.socket(),
1133 server_side=False,
1134 certfile=CERTFILE,
1135 ca_certs=CERTFILE,
1136 cert_reqs=ssl.CERT_NONE,
1137 ssl_version=ssl.PROTOCOL_TLSv1)
1138 s.connect((HOST, server.port))
1139 except ssl.SSLError as x:
Georg Brandl89fad142010-03-14 10:23:39 +00001140 self.fail("Unexpected SSL error: " + str(x))
Bill Janssen58afe4c2008-09-08 16:45:19 +00001141 except Exception as x:
Georg Brandl89fad142010-03-14 10:23:39 +00001142 self.fail("Unexpected exception: " + str(x))
Bill Janssen58afe4c2008-09-08 16:45:19 +00001143 else:
1144 # helper methods for standardising recv* method signatures
1145 def _recv_into():
1146 b = bytearray(b"\0"*100)
1147 count = s.recv_into(b)
1148 return b[:count]
1149
1150 def _recvfrom_into():
1151 b = bytearray(b"\0"*100)
1152 count, addr = s.recvfrom_into(b)
1153 return b[:count]
1154
1155 # (name, method, whether to expect success, *args)
1156 send_methods = [
1157 ('send', s.send, True, []),
1158 ('sendto', s.sendto, False, ["some.address"]),
1159 ('sendall', s.sendall, True, []),
1160 ]
1161 recv_methods = [
1162 ('recv', s.recv, True, []),
1163 ('recvfrom', s.recvfrom, False, ["some.address"]),
1164 ('recv_into', _recv_into, True, []),
1165 ('recvfrom_into', _recvfrom_into, False, []),
1166 ]
1167 data_prefix = "PREFIX_"
1168
1169 for meth_name, send_meth, expect_success, args in send_methods:
1170 indata = data_prefix + meth_name
1171 try:
1172 send_meth(indata.encode('ASCII', 'strict'), *args)
1173 outdata = s.read()
1174 outdata = str(outdata, 'ASCII', 'strict')
1175 if outdata != indata.lower():
Georg Brandl89fad142010-03-14 10:23:39 +00001176 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001177 "While sending with <<{name:s}>> bad data "
1178 "<<{outdata:s}>> ({nout:d}) received; "
1179 "expected <<{indata:s}>> ({nin:d})\n".format(
1180 name=meth_name, outdata=repr(outdata[:20]),
1181 nout=len(outdata),
1182 indata=repr(indata[:20]), nin=len(indata)
1183 )
1184 )
1185 except ValueError as e:
1186 if expect_success:
Georg Brandl89fad142010-03-14 10:23:39 +00001187 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001188 "Failed to send with method <<{name:s}>>; "
1189 "expected to succeed.\n".format(name=meth_name)
1190 )
1191 if not str(e).startswith(meth_name):
Georg Brandl89fad142010-03-14 10:23:39 +00001192 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001193 "Method <<{name:s}>> failed with unexpected "
1194 "exception message: {exp:s}\n".format(
1195 name=meth_name, exp=e
1196 )
1197 )
1198
1199 for meth_name, recv_meth, expect_success, args in recv_methods:
1200 indata = data_prefix + meth_name
1201 try:
1202 s.send(indata.encode('ASCII', 'strict'))
1203 outdata = recv_meth(*args)
1204 outdata = str(outdata, 'ASCII', 'strict')
1205 if outdata != indata.lower():
Georg Brandl89fad142010-03-14 10:23:39 +00001206 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001207 "While receiving with <<{name:s}>> bad data "
1208 "<<{outdata:s}>> ({nout:d}) received; "
1209 "expected <<{indata:s}>> ({nin:d})\n".format(
1210 name=meth_name, outdata=repr(outdata[:20]),
1211 nout=len(outdata),
1212 indata=repr(indata[:20]), nin=len(indata)
1213 )
1214 )
1215 except ValueError as e:
1216 if expect_success:
Georg Brandl89fad142010-03-14 10:23:39 +00001217 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001218 "Failed to receive with method <<{name:s}>>; "
1219 "expected to succeed.\n".format(name=meth_name)
1220 )
1221 if not str(e).startswith(meth_name):
Georg Brandl89fad142010-03-14 10:23:39 +00001222 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001223 "Method <<{name:s}>> failed with unexpected "
1224 "exception message: {exp:s}\n".format(
1225 name=meth_name, exp=e
1226 )
1227 )
1228 # consume data
1229 s.read()
1230
1231 s.write("over\n".encode("ASCII", "strict"))
1232 s.close()
1233 finally:
1234 server.stop()
1235 server.join()
1236
1237
Thomas Woutersed03b412007-08-28 21:37:11 +00001238def test_main(verbose=False):
1239 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001240 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001241
Trent Nelson78520002008-04-10 20:54:35 +00001242 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001243 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1244 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001245 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1246 os.path.dirname(__file__) or os.curdir,
1247 "https_svn_python_org_root.pem")
1248
1249 if (not os.path.exists(CERTFILE) or
1250 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001251 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001252
Thomas Woutersed03b412007-08-28 21:37:11 +00001253 tests = [BasicTests]
1254
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001255 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001256 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001257
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001258 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001259 thread_info = support.threading_setup()
1260 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001261 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001262
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001263 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001264
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001265 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001266 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001267
1268if __name__ == "__main__":
1269 test_main()