blob: eab15ab61a605a36b758793044597fdd25d69e34 [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 errno
Thomas Woutersed03b412007-08-28 21:37:11 +00009import subprocess
10import time
11import os
12import pprint
Jeremy Hylton1afc1692008-06-18 20:49:58 +000013import urllib.parse, urllib.request
Thomas Woutersed03b412007-08-28 21:37:11 +000014import shutil
15import traceback
Bill Janssen54cc54c2007-12-14 22:08:56 +000016import asyncore
Antoine Pitrou78f4a9a2010-04-23 23:12:22 +000017import weakref
Thomas Woutersed03b412007-08-28 21:37:11 +000018
Georg Brandl24420152008-05-26 16:32:26 +000019from http.server import HTTPServer, SimpleHTTPRequestHandler
Thomas Wouters1b7f8912007-09-19 03:06:30 +000020
Thomas Woutersed03b412007-08-28 21:37:11 +000021# Optionally test SSL support, if we have it in the tested platform
22skip_expected = False
23try:
24 import ssl
25except ImportError:
26 skip_expected = True
27
Benjamin Petersonee8712c2008-05-20 21:35:26 +000028HOST = support.HOST
Thomas Woutersed03b412007-08-28 21:37:11 +000029CERTFILE = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +000030SVN_PYTHON_ORG_ROOT_CERT = None
Thomas Woutersed03b412007-08-28 21:37:11 +000031
Thomas Woutersed03b412007-08-28 21:37:11 +000032def handle_error(prefix):
33 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +000034 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000035 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +000036
37
38class BasicTests(unittest.TestCase):
39
Georg Brandlfceab5a2008-01-19 20:08:23 +000040 def testSSLconnect(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000041 if not support.is_resource_enabled('network'):
Georg Brandlfceab5a2008-01-19 20:08:23 +000042 return
43 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
44 cert_reqs=ssl.CERT_NONE)
45 s.connect(("svn.python.org", 443))
46 c = s.getpeercert()
47 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +000048 raise support.TestFailed("Peer cert %s shouldn't be here!")
Georg Brandlfceab5a2008-01-19 20:08:23 +000049 s.close()
50
51 # this should fail because we have no verification certs
52 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
53 cert_reqs=ssl.CERT_REQUIRED)
54 try:
55 s.connect(("svn.python.org", 443))
56 except ssl.SSLError:
57 pass
58 finally:
59 s.close()
60
Thomas Wouters1b7f8912007-09-19 03:06:30 +000061 def testCrucialConstants(self):
62 ssl.PROTOCOL_SSLv2
63 ssl.PROTOCOL_SSLv23
64 ssl.PROTOCOL_SSLv3
65 ssl.PROTOCOL_TLSv1
66 ssl.CERT_NONE
67 ssl.CERT_OPTIONAL
68 ssl.CERT_REQUIRED
Thomas Woutersed03b412007-08-28 21:37:11 +000069
Thomas Wouters1b7f8912007-09-19 03:06:30 +000070 def testRAND(self):
71 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +000072 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000073 sys.stdout.write("\n RAND_status is %d (%s)\n"
74 % (v, (v and "sufficient randomness") or
75 "insufficient randomness"))
Thomas Woutersed03b412007-08-28 21:37:11 +000076 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000077 ssl.RAND_egd(1)
78 except TypeError:
79 pass
Thomas Woutersed03b412007-08-28 21:37:11 +000080 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000081 print("didn't raise TypeError")
82 ssl.RAND_add("this is a random string", 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +000083
Thomas Wouters1b7f8912007-09-19 03:06:30 +000084 def testParseCert(self):
85 # note that this uses an 'unofficial' function in _ssl.c,
86 # provided solely for this test, to exercise the certificate
87 # parsing code
88 p = ssl._ssl._test_decode_cert(CERTFILE, False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +000089 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000090 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
Thomas Woutersed03b412007-08-28 21:37:11 +000091
Thomas Wouters1b7f8912007-09-19 03:06:30 +000092 def testDERtoPEM(self):
93
94 pem = open(SVN_PYTHON_ORG_ROOT_CERT, 'r').read()
95 d1 = ssl.PEM_cert_to_DER_cert(pem)
96 p2 = ssl.DER_cert_to_PEM_cert(d1)
97 d2 = ssl.PEM_cert_to_DER_cert(p2)
98 if (d1 != d2):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000099 raise support.TestFailed("PEM-to-DER or DER-to-PEM translation failed")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000100
Antoine Pitrou78f4a9a2010-04-23 23:12:22 +0000101 @support.cpython_only
102 def test_refcycle(self):
103 # Issue #7943: an SSL object doesn't create reference cycles with
104 # itself.
105 s = socket.socket(socket.AF_INET)
106 ss = ssl.wrap_socket(s)
107 wr = weakref.ref(ss)
108 del ss
109 self.assertEqual(wr(), None)
110
Bill Janssen6e027db2007-11-15 22:23:56 +0000111class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000112
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000113 def testConnect(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000114 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
115 cert_reqs=ssl.CERT_NONE)
116 s.connect(("svn.python.org", 443))
117 c = s.getpeercert()
118 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000119 raise support.TestFailed("Peer cert %s shouldn't be here!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000120 s.close()
121
122 # this should fail because we have no verification certs
123 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
124 cert_reqs=ssl.CERT_REQUIRED)
Thomas Woutersed03b412007-08-28 21:37:11 +0000125 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000126 s.connect(("svn.python.org", 443))
127 except ssl.SSLError:
128 pass
129 finally:
130 s.close()
131
132 # this should succeed because we specify the root cert
133 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
134 cert_reqs=ssl.CERT_REQUIRED,
135 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
136 try:
137 s.connect(("svn.python.org", 443))
138 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000139 raise support.TestFailed("Unexpected exception %s" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000140 finally:
141 s.close()
142
Bill Janssen6e027db2007-11-15 22:23:56 +0000143 def testNonBlockingHandshake(self):
144 s = socket.socket(socket.AF_INET)
145 s.connect(("svn.python.org", 443))
146 s.setblocking(False)
147 s = ssl.wrap_socket(s,
148 cert_reqs=ssl.CERT_NONE,
149 do_handshake_on_connect=False)
150 count = 0
151 while True:
152 try:
153 count += 1
154 s.do_handshake()
155 break
156 except ssl.SSLError as err:
157 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
158 select.select([s], [], [])
159 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
160 select.select([], [s], [])
161 else:
162 raise
163 s.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000164 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000165 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000166
Bill Janssen54cc54c2007-12-14 22:08:56 +0000167 def testFetchServerCert(self):
168
169 pem = ssl.get_server_certificate(("svn.python.org", 443))
170 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000171 raise support.TestFailed("No server certificate on svn.python.org:443!")
Bill Janssen54cc54c2007-12-14 22:08:56 +0000172
173 return
174
175 try:
176 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
177 except ssl.SSLError as x:
178 #should fail
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000179 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000180 sys.stdout.write("%s\n" % x)
181 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000182 raise support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000183
184 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
185 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000186 raise support.TestFailed("No server certificate on svn.python.org:443!")
187 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000188 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
189
Antoine Pitrou754b98c2010-04-22 18:47:06 +0000190 # Test disabled: OPENSSL_VERSION* not available in Python 3.1
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000191 def test_algorithms(self):
Antoine Pitrouae92a722010-04-22 18:46:16 +0000192 if support.verbose:
193 sys.stdout.write("test_algorithms disabled, "
194 "as it fails on some old OpenSSL versions")
195 return
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000196 # Issue #8484: all algorithms should be available when verifying a
197 # certificate.
Antoine Pitrouae92a722010-04-22 18:46:16 +0000198 # SHA256 was added in OpenSSL 0.9.8
199 if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
200 self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000201 # NOTE: https://sha256.tbs-internet.com is another possible test host
202 remote = ("sha2.hboeck.de", 443)
203 sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
204 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
205 cert_reqs=ssl.CERT_REQUIRED,
206 ca_certs=sha256_cert,)
207 with support.transient_internet():
208 try:
209 s.connect(remote)
210 if support.verbose:
211 sys.stdout.write("\nCipher with %r is %r\n" %
212 (remote, s.cipher()))
213 sys.stdout.write("Certificate is:\n%s\n" %
214 pprint.pformat(s.getpeercert()))
215 finally:
216 s.close()
217
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000218
219try:
220 import threading
221except ImportError:
222 _have_threads = False
223else:
224
225 _have_threads = True
226
227 class ThreadedEchoServer(threading.Thread):
228
229 class ConnectionHandler(threading.Thread):
230
231 """A mildly complicated class, because we want it to work both
232 with and without the SSL wrapper around the socket connection, so
233 that we can test the STARTTLS functionality."""
234
Bill Janssen6e027db2007-11-15 22:23:56 +0000235 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000236 self.server = server
237 self.running = False
238 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000239 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000240 self.sock.setblocking(1)
241 self.sslconn = None
242 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000243 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000244
245 def wrap_conn (self):
246 try:
247 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
248 certfile=self.server.certificate,
249 ssl_version=self.server.protocol,
250 ca_certs=self.server.cacerts,
251 cert_reqs=self.server.certreqs)
252 except:
253 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000254 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000255 if not self.server.expect_bad_connects:
256 # here, we want to stop the server, because this shouldn't
257 # happen in the context of our test case
258 self.running = False
259 # normally, we'd just stop here, but for the test
260 # harness, we want to stop the server
261 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000262 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000263 return False
264
265 else:
266 if self.server.certreqs == ssl.CERT_REQUIRED:
267 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000268 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000269 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
270 cert_binary = self.sslconn.getpeercert(True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000271 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000272 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
273 cipher = self.sslconn.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000274 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000275 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
276 return True
277
278 def read(self):
279 if self.sslconn:
280 return self.sslconn.read()
281 else:
282 return self.sock.recv(1024)
283
284 def write(self, bytes):
285 if self.sslconn:
286 return self.sslconn.write(bytes)
287 else:
288 return self.sock.send(bytes)
289
290 def close(self):
291 if self.sslconn:
292 self.sslconn.close()
293 else:
294 self.sock.close()
295
296 def run (self):
297 self.running = True
298 if not self.server.starttls_server:
299 if not self.wrap_conn():
300 return
301 while self.running:
302 try:
303 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000304 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000305 if not msg:
306 # eof, so quit this handler
307 self.running = False
308 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000309 elif amsg.strip() == 'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000310 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000311 sys.stdout.write(" server: client closed connection\n")
312 self.close()
313 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000314 elif (self.server.starttls_server and
315 amsg.strip() == 'STARTTLS'):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000316 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000317 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000318 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000319 if not self.wrap_conn():
320 return
Bill Janssen40a0f662008-08-12 16:56:25 +0000321 elif (self.server.starttls_server and self.sslconn
322 and amsg.strip() == 'ENDTLS'):
323 if support.verbose and self.server.connectionchatty:
324 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
325 self.write("OK\n".encode("ASCII", "strict"))
326 self.sock = self.sslconn.unwrap()
327 self.sslconn = None
328 if support.verbose and self.server.connectionchatty:
329 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000330 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000331 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000332 self.server.connectionchatty):
333 ctype = (self.sslconn and "encrypted") or "unencrypted"
334 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
335 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000336 self.write(amsg.lower().encode('ASCII', 'strict'))
337 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000338 if self.server.chatty:
339 handle_error("Test server failure:\n")
340 self.close()
341 self.running = False
342 # normally, we'd just stop here, but for the test
343 # harness, we want to stop the server
344 self.server.stop()
345 except:
346 handle_error('')
347
Trent Nelson78520002008-04-10 20:54:35 +0000348 def __init__(self, certificate, ssl_version=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000349 certreqs=None, cacerts=None, expect_bad_connects=False,
350 chatty=True, connectionchatty=False, starttls_server=False):
351 if ssl_version is None:
352 ssl_version = ssl.PROTOCOL_TLSv1
353 if certreqs is None:
354 certreqs = ssl.CERT_NONE
355 self.certificate = certificate
356 self.protocol = ssl_version
357 self.certreqs = certreqs
358 self.cacerts = cacerts
359 self.expect_bad_connects = expect_bad_connects
360 self.chatty = chatty
361 self.connectionchatty = connectionchatty
362 self.starttls_server = starttls_server
363 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000364 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000365 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000366 self.active = False
367 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000368 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000369
370 def start (self, flag=None):
371 self.flag = flag
372 threading.Thread.start(self)
373
374 def run (self):
375 self.sock.settimeout(0.5)
376 self.sock.listen(5)
377 self.active = True
378 if self.flag:
379 # signal an event
380 self.flag.set()
381 while self.active:
382 try:
383 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000384 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000385 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000386 + repr(connaddr) + '\n')
387 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000388 handler.start()
389 except socket.timeout:
390 pass
391 except KeyboardInterrupt:
392 self.stop()
393 except:
394 if self.chatty:
395 handle_error("Test server failure:\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000396 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000397
398 def stop (self):
399 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000400
Bill Janssen54cc54c2007-12-14 22:08:56 +0000401 class OurHTTPSServer(threading.Thread):
402
403 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000404
405 class HTTPSServer(HTTPServer):
406
407 def __init__(self, server_address, RequestHandlerClass, certfile):
408
409 HTTPServer.__init__(self, server_address, RequestHandlerClass)
410 # we assume the certfile contains both private key and certificate
411 self.certfile = certfile
412 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000413 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000414 self.allow_reuse_address = True
415
Bill Janssen6e027db2007-11-15 22:23:56 +0000416 def __str__(self):
417 return ('<%s %s:%s>' %
418 (self.__class__.__name__,
419 self.server_name,
420 self.server_port))
421
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000422 def get_request (self):
423 # override this to wrap socket with SSL
424 sock, addr = self.socket.accept()
425 sslconn = ssl.wrap_socket(sock, server_side=True,
426 certfile=self.certfile)
427 return sslconn, addr
428
429 # The methods overridden below this are mainly so that we
430 # can run it in a thread and be able to stop it from another
431 # You probably wouldn't need them in other uses.
432
433 def server_activate(self):
434 # We want to run this in a thread for testing purposes,
435 # so we override this to set timeout, so that we get
436 # a chance to stop the server
437 self.socket.settimeout(0.5)
438 HTTPServer.server_activate(self)
439
440 def serve_forever(self):
441 # We want this to run in a thread, so we use a slightly
442 # modified version of "forever".
443 self.active = True
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000444 while 1:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000445 try:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000446 # We need to lock while handling the request.
447 # Another thread can close the socket after self.active
448 # has been checked and before the request is handled.
449 # This causes an exception when using the closed socket.
450 with self.active_lock:
451 if not self.active:
452 break
453 self.handle_request()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000454 except socket.timeout:
455 pass
456 except KeyboardInterrupt:
457 self.server_close()
458 return
459 except:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000460 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
461 break
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000462 time.sleep(0.1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000463
464 def server_close(self):
465 # Again, we want this to run in a thread, so we need to override
466 # close to clear the "active" flag, so that serve_forever() will
467 # terminate.
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000468 with self.active_lock:
469 HTTPServer.server_close(self)
470 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000471
472 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
473
474 # need to override translate_path to get a known root,
475 # instead of using os.curdir, since the test could be
476 # run from anywhere
477
478 server_version = "TestHTTPS/1.0"
479
480 root = None
481
482 def translate_path(self, path):
483 """Translate a /-separated PATH to the local filename syntax.
484
485 Components that mean special things to the local file system
486 (e.g. drive or directory names) are ignored. (XXX They should
487 probably be diagnosed.)
488
489 """
490 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000491 path = urllib.parse.urlparse(path)[2]
492 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000493 words = path.split('/')
494 words = filter(None, words)
495 path = self.root
496 for word in words:
497 drive, word = os.path.splitdrive(word)
498 head, word = os.path.split(word)
499 if word in self.root: continue
500 path = os.path.join(path, word)
501 return path
502
503 def log_message(self, format, *args):
504
505 # we override this to suppress logging unless "verbose"
506
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000507 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000508 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
509 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000510 self.server.server_port,
511 self.request.cipher(),
512 self.log_date_time_string(),
513 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000514
515
Trent Nelson78520002008-04-10 20:54:35 +0000516 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000517 self.flag = None
518 self.active = False
519 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000520 self.port = support.find_unused_port()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000521 self.server = self.HTTPSServer(
Trent Nelson78520002008-04-10 20:54:35 +0000522 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Thomas Woutersed03b412007-08-28 21:37:11 +0000523 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000524 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000525
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000526 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000527 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000528
529 def start (self, flag=None):
530 self.flag = flag
531 threading.Thread.start(self)
532
Thomas Woutersed03b412007-08-28 21:37:11 +0000533 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000534 self.active = True
535 if self.flag:
536 self.flag.set()
537 self.server.serve_forever()
538 self.active = False
539
540 def stop (self):
541 self.active = False
542 self.server.server_close()
543
544
Bill Janssen54cc54c2007-12-14 22:08:56 +0000545 class AsyncoreEchoServer(threading.Thread):
546
547 # this one's based on asyncore.dispatcher
548
549 class EchoServer (asyncore.dispatcher):
550
551 class ConnectionHandler (asyncore.dispatcher_with_send):
552
553 def __init__(self, conn, certfile):
554 self.socket = ssl.wrap_socket(conn, server_side=True,
555 certfile=certfile,
556 do_handshake_on_connect=False)
557 asyncore.dispatcher_with_send.__init__(self, self.socket)
558 # now we have to do the handshake
559 # we'll just do it the easy way, and block the connection
560 # till it's finished. If we were doing it right, we'd
561 # do this in multiple calls to handle_read...
562 self.do_handshake(block=True)
563
564 def readable(self):
565 if isinstance(self.socket, ssl.SSLSocket):
566 while self.socket.pending() > 0:
567 self.handle_read_event()
568 return True
569
570 def handle_read(self):
571 data = self.recv(1024)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000572 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000573 sys.stdout.write(" server: read %s from client\n" % repr(data))
574 if not data:
575 self.close()
576 else:
577 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
578
579 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000580 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000581 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000582 sys.stdout.write(" server: closed connection %s\n" % self.socket)
583
584 def handle_error(self):
585 raise
586
587 def __init__(self, port, certfile):
588 self.port = port
589 self.certfile = certfile
590 asyncore.dispatcher.__init__(self)
591 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
592 self.bind(('', port))
593 self.listen(5)
594
595 def handle_accept(self):
596 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000597 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000598 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
599 self.ConnectionHandler(sock_obj, self.certfile)
600
601 def handle_error(self):
602 raise
603
Trent Nelson78520002008-04-10 20:54:35 +0000604 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000605 self.flag = None
606 self.active = False
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000607 self.port = support.find_unused_port()
Trent Nelson78520002008-04-10 20:54:35 +0000608 self.server = self.EchoServer(self.port, certfile)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000609 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000610 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000611
612 def __str__(self):
613 return "<%s %s>" % (self.__class__.__name__, self.server)
614
615 def start (self, flag=None):
616 self.flag = flag
617 threading.Thread.start(self)
618
619 def run (self):
620 self.active = True
621 if self.flag:
622 self.flag.set()
623 while self.active:
624 try:
625 asyncore.loop(1)
626 except:
627 pass
628
629 def stop (self):
630 self.active = False
631 self.server.close()
632
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000633 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000634 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000635 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000636 cacerts=CERTFILE, chatty=False,
637 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000638 flag = threading.Event()
639 server.start(flag)
640 # wait for it to start
641 flag.wait()
642 # try to connect
643 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000644 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000645 s = ssl.wrap_socket(socket.socket(),
646 certfile=certfile,
647 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000648 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000649 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000650 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000651 sys.stdout.write("\nSSLError is %s\n" % x)
Bill Janssenddc56692008-07-17 18:17:20 +0000652 except socket.error as x:
653 if support.verbose:
654 sys.stdout.write("\nsocket.error is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000655 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000656 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000657 "Use of invalid cert should have failed!")
658 finally:
659 server.stop()
660 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000661
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000662 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000663 client_certfile, client_protocol=None,
664 indata="FOO\n",
665 chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000666
Trent Nelson78520002008-04-10 20:54:35 +0000667 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000668 certreqs=certreqs,
669 ssl_version=protocol,
670 cacerts=cacertsfile,
671 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000672 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000673 flag = threading.Event()
674 server.start(flag)
675 # wait for it to start
676 flag.wait()
677 # try to connect
678 if client_protocol is None:
679 client_protocol = protocol
680 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000681 s = ssl.wrap_socket(socket.socket(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000682 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000683 certfile=client_certfile,
684 ca_certs=cacertsfile,
685 cert_reqs=certreqs,
686 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000687 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000688 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000689 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000690 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000691 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000692 else:
693 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000694 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000695 sys.stdout.write(
696 " client: sending %s...\n" % (repr(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000697 s.write(indata.encode('ASCII', 'strict'))
Bill Janssen6e027db2007-11-15 22:23:56 +0000698 outdata = s.read()
699 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000700 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000701 sys.stdout.write(" client: read %s\n" % repr(outdata))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000702 outdata = str(outdata, 'ASCII', 'strict')
Bill Janssen6e027db2007-11-15 22:23:56 +0000703 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000704 raise support.TestFailed(
Bill Janssen6e027db2007-11-15 22:23:56 +0000705 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Trent Nelson6b240cd2008-04-10 20:12:06 +0000706 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
707 repr(indata[:min(len(indata),20)].lower()), len(indata)))
708 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000709 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000710 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000711 sys.stdout.write(" client: closing connection.\n")
712 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000713 finally:
714 server.stop()
715 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000716
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000717 def tryProtocolCombo (server_protocol,
718 client_protocol,
719 expectedToWork,
720 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000721
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000722 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000723 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000724
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000725 if certsreqs == ssl.CERT_NONE:
726 certtype = "CERT_NONE"
727 elif certsreqs == ssl.CERT_OPTIONAL:
728 certtype = "CERT_OPTIONAL"
729 elif certsreqs == ssl.CERT_REQUIRED:
730 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000731 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000732 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
733 sys.stdout.write(formatstr %
734 (ssl.get_protocol_name(client_protocol),
735 ssl.get_protocol_name(server_protocol),
736 certtype))
737 try:
738 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000739 CERTFILE, CERTFILE, client_protocol,
740 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000741 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000742 if expectedToWork:
743 raise
744 else:
745 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000746 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000747 "Client protocol %s succeeded with server protocol %s!"
748 % (ssl.get_protocol_name(client_protocol),
749 ssl.get_protocol_name(server_protocol)))
750
751
Bill Janssen6e027db2007-11-15 22:23:56 +0000752 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000753
Trent Nelson6b240cd2008-04-10 20:12:06 +0000754 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000755
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000756 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000757 sys.stdout.write("\n")
758 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
759 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
760 chatty=True, connectionchatty=True)
761
762 def testReadCert(self):
763
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000764 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000765 sys.stdout.write("\n")
766 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000767 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000768 certreqs=ssl.CERT_NONE,
769 ssl_version=ssl.PROTOCOL_SSLv23,
770 cacerts=CERTFILE,
771 chatty=False)
772 flag = threading.Event()
773 server.start(flag)
774 # wait for it to start
775 flag.wait()
776 # try to connect
777 try:
778 try:
779 s = ssl.wrap_socket(socket.socket(),
780 certfile=CERTFILE,
781 ca_certs=CERTFILE,
782 cert_reqs=ssl.CERT_REQUIRED,
783 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000784 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000785 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000786 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000787 "Unexpected SSL error: " + str(x))
788 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000789 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000790 "Unexpected exception: " + str(x))
791 else:
792 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000793 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000794 "Can't SSL-handshake with test server")
795 cert = s.getpeercert()
796 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000797 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000798 "Can't get peer certificate.")
799 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000800 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000801 sys.stdout.write(pprint.pformat(cert) + '\n')
802 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000803 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000804 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000805 "No subject field in certificate: %s." %
806 pprint.pformat(cert))
807 if ((('organizationName', 'Python Software Foundation'),)
808 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000809 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000810 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000811 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000812 s.close()
813 finally:
814 server.stop()
815 server.join()
816
817 def testNULLcert(self):
818 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
819 "nullcert.pem"))
820 def testMalformedCert(self):
821 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
822 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000823 def testWrongCert(self):
824 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
825 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000826 def testMalformedKey(self):
827 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
828 "badkey.pem"))
829
Trent Nelson6b240cd2008-04-10 20:12:06 +0000830 def testRudeShutdown(self):
831
832 listener_ready = threading.Event()
833 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000834 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000835
836 # `listener` runs in a thread. It opens a socket listening on
837 # PORT, and sits in an accept() until the main thread connects.
838 # Then it rudely closes the socket, and sets Event `listener_gone`
839 # to let the main thread know the socket is gone.
840 def listener():
841 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000842 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000843 s.listen(5)
844 listener_ready.set()
845 s.accept()
846 s = None # reclaim the socket object, which also closes it
847 listener_gone.set()
848
849 def connector():
850 listener_ready.wait()
851 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000852 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000853 listener_gone.wait()
854 try:
855 ssl_sock = ssl.wrap_socket(s)
856 except IOError:
857 pass
858 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000859 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000860 'connecting to closed SSL socket should have failed')
861
862 t = threading.Thread(target=listener)
863 t.start()
864 connector()
865 t.join()
866
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000867 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000868 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000869 sys.stdout.write("\n")
870 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
871 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
872 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
873 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
874 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
875 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
876
877 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000878 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000879 sys.stdout.write("\n")
880 try:
881 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000882 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000883 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000884 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000885 sys.stdout.write(
886 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
887 % str(x))
888 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
889 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
890 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
891
892 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
893 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
894 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
895
896 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
897 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
898 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
899
900 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000901 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000902 sys.stdout.write("\n")
903 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
904 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
905 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
906 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
907 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
908 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
909
910 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000911 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000912 sys.stdout.write("\n")
913 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
914 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
915 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
916 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
917 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
918 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
919
920 def testSTARTTLS (self):
921
Bill Janssen40a0f662008-08-12 16:56:25 +0000922 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000923
Trent Nelson78520002008-04-10 20:54:35 +0000924 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000925 ssl_version=ssl.PROTOCOL_TLSv1,
926 starttls_server=True,
927 chatty=True,
928 connectionchatty=True)
929 flag = threading.Event()
930 server.start(flag)
931 # wait for it to start
932 flag.wait()
933 # try to connect
934 wrapped = False
935 try:
936 try:
937 s = socket.socket()
938 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000939 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000940 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000941 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000942 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000943 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000944 sys.stdout.write("\n")
945 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000946 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000947 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000948 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000949 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000950 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000951 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000952 outdata = conn.read()
953 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000954 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000955 outdata = s.recv(1024)
956 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000957 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000958 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000959 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000960 sys.stdout.write(
961 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000962 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000963 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000964 wrapped = True
Bill Janssen40a0f662008-08-12 16:56:25 +0000965 elif (indata == "ENDTLS" and
966 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
967 if support.verbose:
968 msg = str(outdata, 'ASCII', 'replace')
969 sys.stdout.write(
970 " client: read %s from server, ending TLS...\n"
971 % repr(msg))
972 s = conn.unwrap()
973 wrapped = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000974 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000975 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000976 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000977 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000978 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000979 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000980 sys.stdout.write(" client: closing connection.\n")
981 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000982 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000983 else:
Bill Janssen40a0f662008-08-12 16:56:25 +0000984 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000985 if wrapped:
986 conn.close()
987 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000988 s.close()
989 finally:
990 server.stop()
991 server.join()
992
Bill Janssen54cc54c2007-12-14 22:08:56 +0000993 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000994
Trent Nelson78520002008-04-10 20:54:35 +0000995 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000996 flag = threading.Event()
997 server.start(flag)
998 # wait for it to start
999 flag.wait()
1000 # try to connect
1001 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001002 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001003 sys.stdout.write('\n')
1004 d1 = open(CERTFILE, 'rb').read()
1005 d2 = ''
1006 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +00001007 url = 'https://%s:%d/%s' % (
1008 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001009 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +00001010 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001011 if dlen and (int(dlen) > 0):
1012 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001013 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001014 sys.stdout.write(
1015 " client: read %d bytes from remote server '%s'\n"
1016 % (len(d2), server))
1017 f.close()
1018 except:
1019 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001020 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001021 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001022 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001023 else:
1024 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +00001025 print("d1 is", len(d1), repr(d1))
1026 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001027 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001028 "Couldn't fetch data from HTTPS server")
1029 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001030 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001031 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001032 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001033 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001034 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001035 server.join()
1036
Trent Nelson6b240cd2008-04-10 20:12:06 +00001037 def testAsyncoreServer(self):
1038
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001039 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001040 sys.stdout.write("\n")
1041
1042 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001043 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001044 flag = threading.Event()
1045 server.start(flag)
1046 # wait for it to start
1047 flag.wait()
1048 # try to connect
1049 try:
1050 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +00001051 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001052 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001053 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001054 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001055 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001056 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001057 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001058 sys.stdout.write(
1059 " client: sending %s...\n" % (repr(indata)))
1060 s.sendall(indata.encode('ASCII', 'strict'))
1061 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001062 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001063 sys.stdout.write(" client: read %s\n" % repr(outdata))
1064 outdata = str(outdata, 'ASCII', 'strict')
1065 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001066 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001067 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1068 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1069 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1070 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001071 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001072 sys.stdout.write(" client: closing connection.\n")
1073 s.close()
1074 finally:
1075 server.stop()
1076 server.join()
1077
Bill Janssen58afe4c2008-09-08 16:45:19 +00001078 def testAllRecvAndSendMethods(self):
1079
1080 if support.verbose:
1081 sys.stdout.write("\n")
1082
1083 server = ThreadedEchoServer(CERTFILE,
1084 certreqs=ssl.CERT_NONE,
1085 ssl_version=ssl.PROTOCOL_TLSv1,
1086 cacerts=CERTFILE,
1087 chatty=True,
1088 connectionchatty=False)
1089 flag = threading.Event()
1090 server.start(flag)
1091 # wait for it to start
1092 flag.wait()
1093 # try to connect
1094 try:
1095 s = ssl.wrap_socket(socket.socket(),
1096 server_side=False,
1097 certfile=CERTFILE,
1098 ca_certs=CERTFILE,
1099 cert_reqs=ssl.CERT_NONE,
1100 ssl_version=ssl.PROTOCOL_TLSv1)
1101 s.connect((HOST, server.port))
1102 except ssl.SSLError as x:
1103 raise support.TestFailed("Unexpected SSL error: " + str(x))
1104 except Exception as x:
1105 raise support.TestFailed("Unexpected exception: " + str(x))
1106 else:
1107 # helper methods for standardising recv* method signatures
1108 def _recv_into():
1109 b = bytearray(b"\0"*100)
1110 count = s.recv_into(b)
1111 return b[:count]
1112
1113 def _recvfrom_into():
1114 b = bytearray(b"\0"*100)
1115 count, addr = s.recvfrom_into(b)
1116 return b[:count]
1117
1118 # (name, method, whether to expect success, *args)
1119 send_methods = [
1120 ('send', s.send, True, []),
1121 ('sendto', s.sendto, False, ["some.address"]),
1122 ('sendall', s.sendall, True, []),
1123 ]
1124 recv_methods = [
1125 ('recv', s.recv, True, []),
1126 ('recvfrom', s.recvfrom, False, ["some.address"]),
1127 ('recv_into', _recv_into, True, []),
1128 ('recvfrom_into', _recvfrom_into, False, []),
1129 ]
1130 data_prefix = "PREFIX_"
1131
1132 for meth_name, send_meth, expect_success, args in send_methods:
1133 indata = data_prefix + meth_name
1134 try:
1135 send_meth(indata.encode('ASCII', 'strict'), *args)
1136 outdata = s.read()
1137 outdata = str(outdata, 'ASCII', 'strict')
1138 if outdata != indata.lower():
1139 raise support.TestFailed(
1140 "While sending with <<{name:s}>> bad data "
1141 "<<{outdata:s}>> ({nout:d}) received; "
1142 "expected <<{indata:s}>> ({nin:d})\n".format(
1143 name=meth_name, outdata=repr(outdata[:20]),
1144 nout=len(outdata),
1145 indata=repr(indata[:20]), nin=len(indata)
1146 )
1147 )
1148 except ValueError as e:
1149 if expect_success:
1150 raise support.TestFailed(
1151 "Failed to send with method <<{name:s}>>; "
1152 "expected to succeed.\n".format(name=meth_name)
1153 )
1154 if not str(e).startswith(meth_name):
1155 raise support.TestFailed(
1156 "Method <<{name:s}>> failed with unexpected "
1157 "exception message: {exp:s}\n".format(
1158 name=meth_name, exp=e
1159 )
1160 )
1161
1162 for meth_name, recv_meth, expect_success, args in recv_methods:
1163 indata = data_prefix + meth_name
1164 try:
1165 s.send(indata.encode('ASCII', 'strict'))
1166 outdata = recv_meth(*args)
1167 outdata = str(outdata, 'ASCII', 'strict')
1168 if outdata != indata.lower():
1169 raise support.TestFailed(
1170 "While receiving with <<{name:s}>> bad data "
1171 "<<{outdata:s}>> ({nout:d}) received; "
1172 "expected <<{indata:s}>> ({nin:d})\n".format(
1173 name=meth_name, outdata=repr(outdata[:20]),
1174 nout=len(outdata),
1175 indata=repr(indata[:20]), nin=len(indata)
1176 )
1177 )
1178 except ValueError as e:
1179 if expect_success:
1180 raise support.TestFailed(
1181 "Failed to receive with method <<{name:s}>>; "
1182 "expected to succeed.\n".format(name=meth_name)
1183 )
1184 if not str(e).startswith(meth_name):
1185 raise support.TestFailed(
1186 "Method <<{name:s}>> failed with unexpected "
1187 "exception message: {exp:s}\n".format(
1188 name=meth_name, exp=e
1189 )
1190 )
1191 # consume data
1192 s.read()
1193
1194 s.write("over\n".encode("ASCII", "strict"))
1195 s.close()
1196 finally:
1197 server.stop()
1198 server.join()
1199
1200
Thomas Woutersed03b412007-08-28 21:37:11 +00001201def test_main(verbose=False):
1202 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001203 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001204
Trent Nelson78520002008-04-10 20:54:35 +00001205 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001206 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1207 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001208 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1209 os.path.dirname(__file__) or os.curdir,
1210 "https_svn_python_org_root.pem")
1211
1212 if (not os.path.exists(CERTFILE) or
1213 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001214 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001215
Thomas Woutersed03b412007-08-28 21:37:11 +00001216 tests = [BasicTests]
1217
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001218 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001219 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001220
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001221 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001222 thread_info = support.threading_setup()
1223 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001224 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001225
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001226 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001227
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001228 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001229 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001230
1231if __name__ == "__main__":
1232 test_main()