blob: c1c59b526399936313385328d91d70e254f233cc [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
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000221
222try:
223 import threading
224except ImportError:
225 _have_threads = False
226else:
227
228 _have_threads = True
229
230 class ThreadedEchoServer(threading.Thread):
231
232 class ConnectionHandler(threading.Thread):
233
234 """A mildly complicated class, because we want it to work both
235 with and without the SSL wrapper around the socket connection, so
236 that we can test the STARTTLS functionality."""
237
Bill Janssen6e027db2007-11-15 22:23:56 +0000238 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000239 self.server = server
240 self.running = False
241 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000242 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000243 self.sock.setblocking(1)
244 self.sslconn = None
245 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000246 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000247
248 def wrap_conn (self):
249 try:
250 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
251 certfile=self.server.certificate,
252 ssl_version=self.server.protocol,
253 ca_certs=self.server.cacerts,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000254 cert_reqs=self.server.certreqs,
255 ciphers=self.server.ciphers)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000256 except:
257 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000258 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000259 if not self.server.expect_bad_connects:
260 # here, we want to stop the server, because this shouldn't
261 # happen in the context of our test case
262 self.running = False
263 # normally, we'd just stop here, but for the test
264 # harness, we want to stop the server
265 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000266 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000267 return False
268
269 else:
270 if self.server.certreqs == ssl.CERT_REQUIRED:
271 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000272 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000273 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
274 cert_binary = self.sslconn.getpeercert(True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000275 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000276 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
277 cipher = self.sslconn.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000278 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000279 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
280 return True
281
282 def read(self):
283 if self.sslconn:
284 return self.sslconn.read()
285 else:
286 return self.sock.recv(1024)
287
288 def write(self, bytes):
289 if self.sslconn:
290 return self.sslconn.write(bytes)
291 else:
292 return self.sock.send(bytes)
293
294 def close(self):
295 if self.sslconn:
296 self.sslconn.close()
297 else:
298 self.sock.close()
299
300 def run (self):
301 self.running = True
302 if not self.server.starttls_server:
303 if not self.wrap_conn():
304 return
305 while self.running:
306 try:
307 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000308 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000309 if not msg:
310 # eof, so quit this handler
311 self.running = False
312 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000313 elif amsg.strip() == 'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000314 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000315 sys.stdout.write(" server: client closed connection\n")
316 self.close()
317 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000318 elif (self.server.starttls_server and
319 amsg.strip() == 'STARTTLS'):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000320 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000321 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000322 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000323 if not self.wrap_conn():
324 return
Bill Janssen40a0f662008-08-12 16:56:25 +0000325 elif (self.server.starttls_server and self.sslconn
326 and amsg.strip() == 'ENDTLS'):
327 if support.verbose and self.server.connectionchatty:
328 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
329 self.write("OK\n".encode("ASCII", "strict"))
330 self.sock = self.sslconn.unwrap()
331 self.sslconn = None
332 if support.verbose and self.server.connectionchatty:
333 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000334 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000335 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000336 self.server.connectionchatty):
337 ctype = (self.sslconn and "encrypted") or "unencrypted"
338 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
339 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000340 self.write(amsg.lower().encode('ASCII', 'strict'))
341 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000342 if self.server.chatty:
343 handle_error("Test server failure:\n")
344 self.close()
345 self.running = False
346 # normally, we'd just stop here, but for the test
347 # harness, we want to stop the server
348 self.server.stop()
349 except:
350 handle_error('')
351
Trent Nelson78520002008-04-10 20:54:35 +0000352 def __init__(self, certificate, ssl_version=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000353 certreqs=None, cacerts=None, expect_bad_connects=False,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000354 chatty=True, connectionchatty=False, starttls_server=False,
355 ciphers=None):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000356 if ssl_version is None:
357 ssl_version = ssl.PROTOCOL_TLSv1
358 if certreqs is None:
359 certreqs = ssl.CERT_NONE
360 self.certificate = certificate
361 self.protocol = ssl_version
362 self.certreqs = certreqs
363 self.cacerts = cacerts
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000364 self.ciphers = ciphers
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000365 self.expect_bad_connects = expect_bad_connects
366 self.chatty = chatty
367 self.connectionchatty = connectionchatty
368 self.starttls_server = starttls_server
369 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000370 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000371 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000372 self.active = False
373 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000374 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000375
376 def start (self, flag=None):
377 self.flag = flag
378 threading.Thread.start(self)
379
380 def run (self):
381 self.sock.settimeout(0.5)
382 self.sock.listen(5)
383 self.active = True
384 if self.flag:
385 # signal an event
386 self.flag.set()
387 while self.active:
388 try:
389 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000390 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000391 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000392 + repr(connaddr) + '\n')
393 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000394 handler.start()
395 except socket.timeout:
396 pass
397 except KeyboardInterrupt:
398 self.stop()
399 except:
400 if self.chatty:
401 handle_error("Test server failure:\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000402 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000403
404 def stop (self):
405 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000406
Bill Janssen54cc54c2007-12-14 22:08:56 +0000407 class OurHTTPSServer(threading.Thread):
408
409 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000410
411 class HTTPSServer(HTTPServer):
412
413 def __init__(self, server_address, RequestHandlerClass, certfile):
414
415 HTTPServer.__init__(self, server_address, RequestHandlerClass)
416 # we assume the certfile contains both private key and certificate
417 self.certfile = certfile
418 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000419 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000420 self.allow_reuse_address = True
421
Bill Janssen6e027db2007-11-15 22:23:56 +0000422 def __str__(self):
423 return ('<%s %s:%s>' %
424 (self.__class__.__name__,
425 self.server_name,
426 self.server_port))
427
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000428 def get_request (self):
429 # override this to wrap socket with SSL
430 sock, addr = self.socket.accept()
431 sslconn = ssl.wrap_socket(sock, server_side=True,
432 certfile=self.certfile)
433 return sslconn, addr
434
435 # The methods overridden below this are mainly so that we
436 # can run it in a thread and be able to stop it from another
437 # You probably wouldn't need them in other uses.
438
439 def server_activate(self):
440 # We want to run this in a thread for testing purposes,
441 # so we override this to set timeout, so that we get
442 # a chance to stop the server
443 self.socket.settimeout(0.5)
444 HTTPServer.server_activate(self)
445
446 def serve_forever(self):
447 # We want this to run in a thread, so we use a slightly
448 # modified version of "forever".
449 self.active = True
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000450 while 1:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000451 try:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000452 # We need to lock while handling the request.
453 # Another thread can close the socket after self.active
454 # has been checked and before the request is handled.
455 # This causes an exception when using the closed socket.
456 with self.active_lock:
457 if not self.active:
458 break
459 self.handle_request()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000460 except socket.timeout:
461 pass
462 except KeyboardInterrupt:
463 self.server_close()
464 return
465 except:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000466 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
467 break
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000468 time.sleep(0.1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000469
470 def server_close(self):
471 # Again, we want this to run in a thread, so we need to override
472 # close to clear the "active" flag, so that serve_forever() will
473 # terminate.
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000474 with self.active_lock:
475 HTTPServer.server_close(self)
476 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000477
478 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
479
480 # need to override translate_path to get a known root,
481 # instead of using os.curdir, since the test could be
482 # run from anywhere
483
484 server_version = "TestHTTPS/1.0"
485
486 root = None
487
488 def translate_path(self, path):
489 """Translate a /-separated PATH to the local filename syntax.
490
491 Components that mean special things to the local file system
492 (e.g. drive or directory names) are ignored. (XXX They should
493 probably be diagnosed.)
494
495 """
496 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000497 path = urllib.parse.urlparse(path)[2]
498 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000499 words = path.split('/')
500 words = filter(None, words)
501 path = self.root
502 for word in words:
503 drive, word = os.path.splitdrive(word)
504 head, word = os.path.split(word)
505 if word in self.root: continue
506 path = os.path.join(path, word)
507 return path
508
509 def log_message(self, format, *args):
510
511 # we override this to suppress logging unless "verbose"
512
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000513 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000514 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
515 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000516 self.server.server_port,
517 self.request.cipher(),
518 self.log_date_time_string(),
519 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000520
521
Trent Nelson78520002008-04-10 20:54:35 +0000522 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000523 self.flag = None
524 self.active = False
525 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000526 self.port = support.find_unused_port()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000527 self.server = self.HTTPSServer(
Trent Nelson78520002008-04-10 20:54:35 +0000528 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Thomas Woutersed03b412007-08-28 21:37:11 +0000529 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000530 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000531
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000532 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000533 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000534
535 def start (self, flag=None):
536 self.flag = flag
537 threading.Thread.start(self)
538
Thomas Woutersed03b412007-08-28 21:37:11 +0000539 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000540 self.active = True
541 if self.flag:
542 self.flag.set()
543 self.server.serve_forever()
544 self.active = False
545
546 def stop (self):
547 self.active = False
548 self.server.server_close()
549
550
Bill Janssen54cc54c2007-12-14 22:08:56 +0000551 class AsyncoreEchoServer(threading.Thread):
552
553 # this one's based on asyncore.dispatcher
554
555 class EchoServer (asyncore.dispatcher):
556
557 class ConnectionHandler (asyncore.dispatcher_with_send):
558
559 def __init__(self, conn, certfile):
560 self.socket = ssl.wrap_socket(conn, server_side=True,
561 certfile=certfile,
562 do_handshake_on_connect=False)
563 asyncore.dispatcher_with_send.__init__(self, self.socket)
564 # now we have to do the handshake
565 # we'll just do it the easy way, and block the connection
566 # till it's finished. If we were doing it right, we'd
567 # do this in multiple calls to handle_read...
568 self.do_handshake(block=True)
569
570 def readable(self):
571 if isinstance(self.socket, ssl.SSLSocket):
572 while self.socket.pending() > 0:
573 self.handle_read_event()
574 return True
575
576 def handle_read(self):
577 data = self.recv(1024)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000578 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000579 sys.stdout.write(" server: read %s from client\n" % repr(data))
580 if not data:
581 self.close()
582 else:
583 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
584
585 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000586 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000587 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000588 sys.stdout.write(" server: closed connection %s\n" % self.socket)
589
590 def handle_error(self):
591 raise
592
593 def __init__(self, port, certfile):
594 self.port = port
595 self.certfile = certfile
596 asyncore.dispatcher.__init__(self)
597 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
598 self.bind(('', port))
599 self.listen(5)
600
601 def handle_accept(self):
602 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000603 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000604 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
605 self.ConnectionHandler(sock_obj, self.certfile)
606
607 def handle_error(self):
608 raise
609
Trent Nelson78520002008-04-10 20:54:35 +0000610 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000611 self.flag = None
612 self.active = False
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000613 self.port = support.find_unused_port()
Trent Nelson78520002008-04-10 20:54:35 +0000614 self.server = self.EchoServer(self.port, certfile)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000615 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000616 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000617
618 def __str__(self):
619 return "<%s %s>" % (self.__class__.__name__, self.server)
620
621 def start (self, flag=None):
622 self.flag = flag
623 threading.Thread.start(self)
624
625 def run (self):
626 self.active = True
627 if self.flag:
628 self.flag.set()
629 while self.active:
630 try:
631 asyncore.loop(1)
632 except:
633 pass
634
635 def stop (self):
636 self.active = False
637 self.server.close()
638
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000639 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000640 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000641 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000642 cacerts=CERTFILE, chatty=False,
643 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000644 flag = threading.Event()
645 server.start(flag)
646 # wait for it to start
647 flag.wait()
648 # try to connect
649 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000650 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000651 s = ssl.wrap_socket(socket.socket(),
652 certfile=certfile,
653 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000654 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000655 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000656 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000657 sys.stdout.write("\nSSLError is %s\n" % x)
Bill Janssenddc56692008-07-17 18:17:20 +0000658 except socket.error as x:
659 if support.verbose:
660 sys.stdout.write("\nsocket.error is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000661 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000662 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000663 "Use of invalid cert should have failed!")
664 finally:
665 server.stop()
666 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000667
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000668 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000669 client_certfile, client_protocol=None,
670 indata="FOO\n",
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000671 ciphers=None, chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000672
Trent Nelson78520002008-04-10 20:54:35 +0000673 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000674 certreqs=certreqs,
675 ssl_version=protocol,
676 cacerts=cacertsfile,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000677 ciphers=ciphers,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000678 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000679 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000680 flag = threading.Event()
681 server.start(flag)
682 # wait for it to start
683 flag.wait()
684 # try to connect
685 if client_protocol is None:
686 client_protocol = protocol
687 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000688 s = ssl.wrap_socket(socket.socket(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000689 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000690 certfile=client_certfile,
691 ca_certs=cacertsfile,
692 cert_reqs=certreqs,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000693 ciphers=ciphers,
Bill Janssen6e027db2007-11-15 22:23:56 +0000694 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000695 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000696 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000697 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000698 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000699 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000700 else:
Antoine Pitrou7d7aede2009-11-25 18:55:32 +0000701 bindata = indata.encode('ASCII', 'strict')
702 for arg in [bindata, bytearray(bindata), memoryview(bindata)]:
703 if connectionchatty:
704 if support.verbose:
705 sys.stdout.write(
706 " client: sending %s...\n" % (repr(indata)))
707 s.write(arg)
708 outdata = s.read()
709 if connectionchatty:
710 if support.verbose:
711 sys.stdout.write(" client: read %s\n" % repr(outdata))
712 outdata = str(outdata, 'ASCII', 'strict')
713 if outdata != indata.lower():
714 raise support.TestFailed(
715 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
716 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
717 repr(indata[:min(len(indata),20)].lower()), len(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000718 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000719 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000720 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000721 sys.stdout.write(" client: closing connection.\n")
722 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000723 finally:
724 server.stop()
725 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000726
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000727 def tryProtocolCombo (server_protocol,
728 client_protocol,
729 expectedToWork,
730 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000731
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000732 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000733 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000734
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000735 if certsreqs == ssl.CERT_NONE:
736 certtype = "CERT_NONE"
737 elif certsreqs == ssl.CERT_OPTIONAL:
738 certtype = "CERT_OPTIONAL"
739 elif certsreqs == ssl.CERT_REQUIRED:
740 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000741 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000742 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
743 sys.stdout.write(formatstr %
744 (ssl.get_protocol_name(client_protocol),
745 ssl.get_protocol_name(server_protocol),
746 certtype))
747 try:
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000748 # NOTE: we must enable "ALL" ciphers, otherwise an SSLv23 client
749 # will send an SSLv3 hello (rather than SSLv2) starting from
750 # OpenSSL 1.0.0 (see issue #8322).
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000751 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000752 CERTFILE, CERTFILE, client_protocol,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000753 ciphers="ALL",
Bill Janssen6e027db2007-11-15 22:23:56 +0000754 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000755 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000756 if expectedToWork:
757 raise
758 else:
759 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000760 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000761 "Client protocol %s succeeded with server protocol %s!"
762 % (ssl.get_protocol_name(client_protocol),
763 ssl.get_protocol_name(server_protocol)))
764
765
Bill Janssen6e027db2007-11-15 22:23:56 +0000766 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000767
Trent Nelson6b240cd2008-04-10 20:12:06 +0000768 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000769
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000770 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000771 sys.stdout.write("\n")
772 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
773 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
774 chatty=True, connectionchatty=True)
775
776 def testReadCert(self):
777
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000778 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000779 sys.stdout.write("\n")
780 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000781 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000782 certreqs=ssl.CERT_NONE,
783 ssl_version=ssl.PROTOCOL_SSLv23,
784 cacerts=CERTFILE,
785 chatty=False)
786 flag = threading.Event()
787 server.start(flag)
788 # wait for it to start
789 flag.wait()
790 # try to connect
791 try:
792 try:
793 s = ssl.wrap_socket(socket.socket(),
794 certfile=CERTFILE,
795 ca_certs=CERTFILE,
796 cert_reqs=ssl.CERT_REQUIRED,
797 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000798 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000799 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000800 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000801 "Unexpected SSL error: " + str(x))
802 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000803 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000804 "Unexpected exception: " + str(x))
805 else:
806 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000807 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000808 "Can't SSL-handshake with test server")
809 cert = s.getpeercert()
810 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000811 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000812 "Can't get peer certificate.")
813 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000814 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000815 sys.stdout.write(pprint.pformat(cert) + '\n')
816 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000817 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000818 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000819 "No subject field in certificate: %s." %
820 pprint.pformat(cert))
821 if ((('organizationName', 'Python Software Foundation'),)
822 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000823 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000824 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000825 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000826 s.close()
827 finally:
828 server.stop()
829 server.join()
830
831 def testNULLcert(self):
832 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
833 "nullcert.pem"))
834 def testMalformedCert(self):
835 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
836 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000837 def testWrongCert(self):
838 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
839 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000840 def testMalformedKey(self):
841 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
842 "badkey.pem"))
843
Trent Nelson6b240cd2008-04-10 20:12:06 +0000844 def testRudeShutdown(self):
845
846 listener_ready = threading.Event()
847 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000848 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000849
850 # `listener` runs in a thread. It opens a socket listening on
851 # PORT, and sits in an accept() until the main thread connects.
852 # Then it rudely closes the socket, and sets Event `listener_gone`
853 # to let the main thread know the socket is gone.
854 def listener():
855 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000856 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000857 s.listen(5)
858 listener_ready.set()
859 s.accept()
860 s = None # reclaim the socket object, which also closes it
861 listener_gone.set()
862
863 def connector():
864 listener_ready.wait()
865 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000866 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000867 listener_gone.wait()
868 try:
869 ssl_sock = ssl.wrap_socket(s)
870 except IOError:
871 pass
872 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000873 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000874 'connecting to closed SSL socket should have failed')
875
876 t = threading.Thread(target=listener)
877 t.start()
878 connector()
879 t.join()
880
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000881 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000882 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000883 sys.stdout.write("\n")
884 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
885 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
886 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
887 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
888 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
889 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
890
891 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000892 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000893 sys.stdout.write("\n")
894 try:
895 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000896 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000897 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000898 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000899 sys.stdout.write(
900 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
901 % str(x))
902 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
903 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
904 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
905
906 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
907 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
908 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
909
910 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
911 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
912 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
913
914 def testProtocolSSL3(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 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
918 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
919 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
920 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
921 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
922 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
923
924 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000925 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000926 sys.stdout.write("\n")
927 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
928 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
929 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
930 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
931 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
932 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
933
934 def testSTARTTLS (self):
935
Bill Janssen40a0f662008-08-12 16:56:25 +0000936 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000937
Trent Nelson78520002008-04-10 20:54:35 +0000938 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000939 ssl_version=ssl.PROTOCOL_TLSv1,
940 starttls_server=True,
941 chatty=True,
942 connectionchatty=True)
943 flag = threading.Event()
944 server.start(flag)
945 # wait for it to start
946 flag.wait()
947 # try to connect
948 wrapped = False
949 try:
950 try:
951 s = socket.socket()
952 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000953 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000954 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000955 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000956 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000957 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000958 sys.stdout.write("\n")
959 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000960 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000961 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000962 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000963 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000964 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000965 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000966 outdata = conn.read()
967 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000968 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000969 outdata = s.recv(1024)
970 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000971 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000972 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000973 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000974 sys.stdout.write(
975 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000976 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000977 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000978 wrapped = True
Bill Janssen40a0f662008-08-12 16:56:25 +0000979 elif (indata == "ENDTLS" and
980 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
981 if support.verbose:
982 msg = str(outdata, 'ASCII', 'replace')
983 sys.stdout.write(
984 " client: read %s from server, ending TLS...\n"
985 % repr(msg))
986 s = conn.unwrap()
987 wrapped = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000988 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000989 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000990 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000991 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000992 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000993 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000994 sys.stdout.write(" client: closing connection.\n")
995 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000996 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000997 else:
Bill Janssen40a0f662008-08-12 16:56:25 +0000998 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000999 if wrapped:
1000 conn.close()
1001 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001002 s.close()
1003 finally:
1004 server.stop()
1005 server.join()
1006
Bill Janssen54cc54c2007-12-14 22:08:56 +00001007 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +00001008
Trent Nelson78520002008-04-10 20:54:35 +00001009 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001010 flag = threading.Event()
1011 server.start(flag)
1012 # wait for it to start
1013 flag.wait()
1014 # try to connect
1015 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001016 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001017 sys.stdout.write('\n')
1018 d1 = open(CERTFILE, 'rb').read()
1019 d2 = ''
1020 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +00001021 url = 'https://%s:%d/%s' % (
1022 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001023 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +00001024 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001025 if dlen and (int(dlen) > 0):
1026 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001027 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001028 sys.stdout.write(
1029 " client: read %d bytes from remote server '%s'\n"
1030 % (len(d2), server))
1031 f.close()
1032 except:
1033 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001034 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001035 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001036 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001037 else:
1038 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +00001039 print("d1 is", len(d1), repr(d1))
1040 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001041 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001042 "Couldn't fetch data from HTTPS server")
1043 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001044 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001045 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001046 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001047 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001048 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001049 server.join()
1050
Trent Nelson6b240cd2008-04-10 20:12:06 +00001051 def testAsyncoreServer(self):
1052
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001053 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001054 sys.stdout.write("\n")
1055
1056 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001057 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001058 flag = threading.Event()
1059 server.start(flag)
1060 # wait for it to start
1061 flag.wait()
1062 # try to connect
1063 try:
1064 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +00001065 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001066 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001067 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001068 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001069 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001070 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001071 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001072 sys.stdout.write(
1073 " client: sending %s...\n" % (repr(indata)))
1074 s.sendall(indata.encode('ASCII', 'strict'))
1075 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001076 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001077 sys.stdout.write(" client: read %s\n" % repr(outdata))
1078 outdata = str(outdata, 'ASCII', 'strict')
1079 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001080 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001081 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1082 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1083 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1084 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001085 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001086 sys.stdout.write(" client: closing connection.\n")
1087 s.close()
1088 finally:
1089 server.stop()
1090 server.join()
1091
Bill Janssen58afe4c2008-09-08 16:45:19 +00001092 def testAllRecvAndSendMethods(self):
1093
1094 if support.verbose:
1095 sys.stdout.write("\n")
1096
1097 server = ThreadedEchoServer(CERTFILE,
1098 certreqs=ssl.CERT_NONE,
1099 ssl_version=ssl.PROTOCOL_TLSv1,
1100 cacerts=CERTFILE,
1101 chatty=True,
1102 connectionchatty=False)
1103 flag = threading.Event()
1104 server.start(flag)
1105 # wait for it to start
1106 flag.wait()
1107 # try to connect
1108 try:
1109 s = ssl.wrap_socket(socket.socket(),
1110 server_side=False,
1111 certfile=CERTFILE,
1112 ca_certs=CERTFILE,
1113 cert_reqs=ssl.CERT_NONE,
1114 ssl_version=ssl.PROTOCOL_TLSv1)
1115 s.connect((HOST, server.port))
1116 except ssl.SSLError as x:
Georg Brandl89fad142010-03-14 10:23:39 +00001117 self.fail("Unexpected SSL error: " + str(x))
Bill Janssen58afe4c2008-09-08 16:45:19 +00001118 except Exception as x:
Georg Brandl89fad142010-03-14 10:23:39 +00001119 self.fail("Unexpected exception: " + str(x))
Bill Janssen58afe4c2008-09-08 16:45:19 +00001120 else:
1121 # helper methods for standardising recv* method signatures
1122 def _recv_into():
1123 b = bytearray(b"\0"*100)
1124 count = s.recv_into(b)
1125 return b[:count]
1126
1127 def _recvfrom_into():
1128 b = bytearray(b"\0"*100)
1129 count, addr = s.recvfrom_into(b)
1130 return b[:count]
1131
1132 # (name, method, whether to expect success, *args)
1133 send_methods = [
1134 ('send', s.send, True, []),
1135 ('sendto', s.sendto, False, ["some.address"]),
1136 ('sendall', s.sendall, True, []),
1137 ]
1138 recv_methods = [
1139 ('recv', s.recv, True, []),
1140 ('recvfrom', s.recvfrom, False, ["some.address"]),
1141 ('recv_into', _recv_into, True, []),
1142 ('recvfrom_into', _recvfrom_into, False, []),
1143 ]
1144 data_prefix = "PREFIX_"
1145
1146 for meth_name, send_meth, expect_success, args in send_methods:
1147 indata = data_prefix + meth_name
1148 try:
1149 send_meth(indata.encode('ASCII', 'strict'), *args)
1150 outdata = s.read()
1151 outdata = str(outdata, 'ASCII', 'strict')
1152 if outdata != indata.lower():
Georg Brandl89fad142010-03-14 10:23:39 +00001153 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001154 "While sending with <<{name:s}>> bad data "
1155 "<<{outdata:s}>> ({nout:d}) received; "
1156 "expected <<{indata:s}>> ({nin:d})\n".format(
1157 name=meth_name, outdata=repr(outdata[:20]),
1158 nout=len(outdata),
1159 indata=repr(indata[:20]), nin=len(indata)
1160 )
1161 )
1162 except ValueError as e:
1163 if expect_success:
Georg Brandl89fad142010-03-14 10:23:39 +00001164 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001165 "Failed to send with method <<{name:s}>>; "
1166 "expected to succeed.\n".format(name=meth_name)
1167 )
1168 if not str(e).startswith(meth_name):
Georg Brandl89fad142010-03-14 10:23:39 +00001169 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001170 "Method <<{name:s}>> failed with unexpected "
1171 "exception message: {exp:s}\n".format(
1172 name=meth_name, exp=e
1173 )
1174 )
1175
1176 for meth_name, recv_meth, expect_success, args in recv_methods:
1177 indata = data_prefix + meth_name
1178 try:
1179 s.send(indata.encode('ASCII', 'strict'))
1180 outdata = recv_meth(*args)
1181 outdata = str(outdata, 'ASCII', 'strict')
1182 if outdata != indata.lower():
Georg Brandl89fad142010-03-14 10:23:39 +00001183 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001184 "While receiving with <<{name:s}>> bad data "
1185 "<<{outdata:s}>> ({nout:d}) received; "
1186 "expected <<{indata:s}>> ({nin:d})\n".format(
1187 name=meth_name, outdata=repr(outdata[:20]),
1188 nout=len(outdata),
1189 indata=repr(indata[:20]), nin=len(indata)
1190 )
1191 )
1192 except ValueError as e:
1193 if expect_success:
Georg Brandl89fad142010-03-14 10:23:39 +00001194 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001195 "Failed to receive with method <<{name:s}>>; "
1196 "expected to succeed.\n".format(name=meth_name)
1197 )
1198 if not str(e).startswith(meth_name):
Georg Brandl89fad142010-03-14 10:23:39 +00001199 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001200 "Method <<{name:s}>> failed with unexpected "
1201 "exception message: {exp:s}\n".format(
1202 name=meth_name, exp=e
1203 )
1204 )
1205 # consume data
1206 s.read()
1207
1208 s.write("over\n".encode("ASCII", "strict"))
1209 s.close()
1210 finally:
1211 server.stop()
1212 server.join()
1213
1214
Thomas Woutersed03b412007-08-28 21:37:11 +00001215def test_main(verbose=False):
1216 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001217 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001218
Trent Nelson78520002008-04-10 20:54:35 +00001219 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001220 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1221 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001222 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1223 os.path.dirname(__file__) or os.curdir,
1224 "https_svn_python_org_root.pem")
1225
1226 if (not os.path.exists(CERTFILE) or
1227 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001228 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001229
Thomas Woutersed03b412007-08-28 21:37:11 +00001230 tests = [BasicTests]
1231
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001232 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001233 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001234
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001235 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001236 thread_info = support.threading_setup()
1237 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001238 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001239
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001240 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001241
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001242 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001243 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001244
1245if __name__ == "__main__":
1246 test_main()