blob: 91d17b5d111915eb7dfd0f98345aa9a40d564367 [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
Thomas Woutersed03b412007-08-28 21:37:11 +000017
Georg Brandl24420152008-05-26 16:32:26 +000018from http.server import HTTPServer, SimpleHTTPRequestHandler
Thomas Wouters1b7f8912007-09-19 03:06:30 +000019
Thomas Woutersed03b412007-08-28 21:37:11 +000020# Optionally test SSL support, if we have it in the tested platform
21skip_expected = False
22try:
23 import ssl
24except ImportError:
25 skip_expected = True
26
Benjamin Petersonee8712c2008-05-20 21:35:26 +000027HOST = support.HOST
Thomas Woutersed03b412007-08-28 21:37:11 +000028CERTFILE = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +000029SVN_PYTHON_ORG_ROOT_CERT = None
Thomas Woutersed03b412007-08-28 21:37:11 +000030
Thomas Woutersed03b412007-08-28 21:37:11 +000031def handle_error(prefix):
32 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +000033 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000034 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +000035
36
37class BasicTests(unittest.TestCase):
38
Georg Brandlfceab5a2008-01-19 20:08:23 +000039 def testSSLconnect(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000040 if not support.is_resource_enabled('network'):
Georg Brandlfceab5a2008-01-19 20:08:23 +000041 return
42 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
43 cert_reqs=ssl.CERT_NONE)
44 s.connect(("svn.python.org", 443))
45 c = s.getpeercert()
46 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +000047 raise support.TestFailed("Peer cert %s shouldn't be here!")
Georg Brandlfceab5a2008-01-19 20:08:23 +000048 s.close()
49
50 # this should fail because we have no verification certs
51 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
52 cert_reqs=ssl.CERT_REQUIRED)
53 try:
54 s.connect(("svn.python.org", 443))
55 except ssl.SSLError:
56 pass
57 finally:
58 s.close()
59
Thomas Wouters1b7f8912007-09-19 03:06:30 +000060 def testCrucialConstants(self):
61 ssl.PROTOCOL_SSLv2
62 ssl.PROTOCOL_SSLv23
63 ssl.PROTOCOL_SSLv3
64 ssl.PROTOCOL_TLSv1
65 ssl.CERT_NONE
66 ssl.CERT_OPTIONAL
67 ssl.CERT_REQUIRED
Thomas Woutersed03b412007-08-28 21:37:11 +000068
Thomas Wouters1b7f8912007-09-19 03:06:30 +000069 def testRAND(self):
70 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +000071 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000072 sys.stdout.write("\n RAND_status is %d (%s)\n"
73 % (v, (v and "sufficient randomness") or
74 "insufficient randomness"))
Thomas Woutersed03b412007-08-28 21:37:11 +000075 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000076 ssl.RAND_egd(1)
77 except TypeError:
78 pass
Thomas Woutersed03b412007-08-28 21:37:11 +000079 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000080 print("didn't raise TypeError")
81 ssl.RAND_add("this is a random string", 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +000082
Thomas Wouters1b7f8912007-09-19 03:06:30 +000083 def testParseCert(self):
84 # note that this uses an 'unofficial' function in _ssl.c,
85 # provided solely for this test, to exercise the certificate
86 # parsing code
87 p = ssl._ssl._test_decode_cert(CERTFILE, False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +000088 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000089 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
Thomas Woutersed03b412007-08-28 21:37:11 +000090
Thomas Wouters1b7f8912007-09-19 03:06:30 +000091 def testDERtoPEM(self):
92
93 pem = open(SVN_PYTHON_ORG_ROOT_CERT, 'r').read()
94 d1 = ssl.PEM_cert_to_DER_cert(pem)
95 p2 = ssl.DER_cert_to_PEM_cert(d1)
96 d2 = ssl.PEM_cert_to_DER_cert(p2)
97 if (d1 != d2):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000098 raise support.TestFailed("PEM-to-DER or DER-to-PEM translation failed")
Thomas Wouters1b7f8912007-09-19 03:06:30 +000099
Bill Janssen6e027db2007-11-15 22:23:56 +0000100class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000101
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000102 def testConnect(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000103 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
104 cert_reqs=ssl.CERT_NONE)
105 s.connect(("svn.python.org", 443))
106 c = s.getpeercert()
107 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000108 raise support.TestFailed("Peer cert %s shouldn't be here!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000109 s.close()
110
111 # this should fail because we have no verification certs
112 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
113 cert_reqs=ssl.CERT_REQUIRED)
Thomas Woutersed03b412007-08-28 21:37:11 +0000114 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000115 s.connect(("svn.python.org", 443))
116 except ssl.SSLError:
117 pass
118 finally:
119 s.close()
120
121 # this should succeed because we specify the root cert
122 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
123 cert_reqs=ssl.CERT_REQUIRED,
124 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
125 try:
126 s.connect(("svn.python.org", 443))
127 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000128 raise support.TestFailed("Unexpected exception %s" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000129 finally:
130 s.close()
131
Bill Janssen6e027db2007-11-15 22:23:56 +0000132 def testNonBlockingHandshake(self):
133 s = socket.socket(socket.AF_INET)
134 s.connect(("svn.python.org", 443))
135 s.setblocking(False)
136 s = ssl.wrap_socket(s,
137 cert_reqs=ssl.CERT_NONE,
138 do_handshake_on_connect=False)
139 count = 0
140 while True:
141 try:
142 count += 1
143 s.do_handshake()
144 break
145 except ssl.SSLError as err:
146 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
147 select.select([s], [], [])
148 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
149 select.select([], [s], [])
150 else:
151 raise
152 s.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000153 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000154 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000155
Bill Janssen54cc54c2007-12-14 22:08:56 +0000156 def testFetchServerCert(self):
157
158 pem = ssl.get_server_certificate(("svn.python.org", 443))
159 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000160 raise support.TestFailed("No server certificate on svn.python.org:443!")
Bill Janssen54cc54c2007-12-14 22:08:56 +0000161
162 return
163
164 try:
165 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
166 except ssl.SSLError as x:
167 #should fail
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000168 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000169 sys.stdout.write("%s\n" % x)
170 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000171 raise support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000172
173 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
174 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000175 raise support.TestFailed("No server certificate on svn.python.org:443!")
176 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000177 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
178
Antoine Pitrouae92a722010-04-22 18:46:16 +0000179 # Test disabled: OPENSSL_VERSION* not available in Python 2.6
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000180 def test_algorithms(self):
Antoine Pitrouae92a722010-04-22 18:46:16 +0000181 if support.verbose:
182 sys.stdout.write("test_algorithms disabled, "
183 "as it fails on some old OpenSSL versions")
184 return
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000185 # Issue #8484: all algorithms should be available when verifying a
186 # certificate.
Antoine Pitrouae92a722010-04-22 18:46:16 +0000187 # SHA256 was added in OpenSSL 0.9.8
188 if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
189 self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000190 # NOTE: https://sha256.tbs-internet.com is another possible test host
191 remote = ("sha2.hboeck.de", 443)
192 sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
193 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
194 cert_reqs=ssl.CERT_REQUIRED,
195 ca_certs=sha256_cert,)
196 with support.transient_internet():
197 try:
198 s.connect(remote)
199 if support.verbose:
200 sys.stdout.write("\nCipher with %r is %r\n" %
201 (remote, s.cipher()))
202 sys.stdout.write("Certificate is:\n%s\n" %
203 pprint.pformat(s.getpeercert()))
204 finally:
205 s.close()
206
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000207
208try:
209 import threading
210except ImportError:
211 _have_threads = False
212else:
213
214 _have_threads = True
215
216 class ThreadedEchoServer(threading.Thread):
217
218 class ConnectionHandler(threading.Thread):
219
220 """A mildly complicated class, because we want it to work both
221 with and without the SSL wrapper around the socket connection, so
222 that we can test the STARTTLS functionality."""
223
Bill Janssen6e027db2007-11-15 22:23:56 +0000224 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000225 self.server = server
226 self.running = False
227 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000228 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000229 self.sock.setblocking(1)
230 self.sslconn = None
231 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000232 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000233
234 def wrap_conn (self):
235 try:
236 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
237 certfile=self.server.certificate,
238 ssl_version=self.server.protocol,
239 ca_certs=self.server.cacerts,
240 cert_reqs=self.server.certreqs)
241 except:
242 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000243 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000244 if not self.server.expect_bad_connects:
245 # here, we want to stop the server, because this shouldn't
246 # happen in the context of our test case
247 self.running = False
248 # normally, we'd just stop here, but for the test
249 # harness, we want to stop the server
250 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000251 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000252 return False
253
254 else:
255 if self.server.certreqs == ssl.CERT_REQUIRED:
256 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000257 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000258 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
259 cert_binary = self.sslconn.getpeercert(True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000260 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000261 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
262 cipher = self.sslconn.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000263 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000264 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
265 return True
266
267 def read(self):
268 if self.sslconn:
269 return self.sslconn.read()
270 else:
271 return self.sock.recv(1024)
272
273 def write(self, bytes):
274 if self.sslconn:
275 return self.sslconn.write(bytes)
276 else:
277 return self.sock.send(bytes)
278
279 def close(self):
280 if self.sslconn:
281 self.sslconn.close()
282 else:
283 self.sock.close()
284
285 def run (self):
286 self.running = True
287 if not self.server.starttls_server:
288 if not self.wrap_conn():
289 return
290 while self.running:
291 try:
292 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000293 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000294 if not msg:
295 # eof, so quit this handler
296 self.running = False
297 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000298 elif amsg.strip() == 'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000299 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000300 sys.stdout.write(" server: client closed connection\n")
301 self.close()
302 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000303 elif (self.server.starttls_server and
304 amsg.strip() == 'STARTTLS'):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000305 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000306 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000307 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000308 if not self.wrap_conn():
309 return
Bill Janssen40a0f662008-08-12 16:56:25 +0000310 elif (self.server.starttls_server and self.sslconn
311 and amsg.strip() == 'ENDTLS'):
312 if support.verbose and self.server.connectionchatty:
313 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
314 self.write("OK\n".encode("ASCII", "strict"))
315 self.sock = self.sslconn.unwrap()
316 self.sslconn = None
317 if support.verbose and self.server.connectionchatty:
318 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000319 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000320 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000321 self.server.connectionchatty):
322 ctype = (self.sslconn and "encrypted") or "unencrypted"
323 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
324 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000325 self.write(amsg.lower().encode('ASCII', 'strict'))
326 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000327 if self.server.chatty:
328 handle_error("Test server failure:\n")
329 self.close()
330 self.running = False
331 # normally, we'd just stop here, but for the test
332 # harness, we want to stop the server
333 self.server.stop()
334 except:
335 handle_error('')
336
Trent Nelson78520002008-04-10 20:54:35 +0000337 def __init__(self, certificate, ssl_version=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000338 certreqs=None, cacerts=None, expect_bad_connects=False,
339 chatty=True, connectionchatty=False, starttls_server=False):
340 if ssl_version is None:
341 ssl_version = ssl.PROTOCOL_TLSv1
342 if certreqs is None:
343 certreqs = ssl.CERT_NONE
344 self.certificate = certificate
345 self.protocol = ssl_version
346 self.certreqs = certreqs
347 self.cacerts = cacerts
348 self.expect_bad_connects = expect_bad_connects
349 self.chatty = chatty
350 self.connectionchatty = connectionchatty
351 self.starttls_server = starttls_server
352 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000353 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000354 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000355 self.active = False
356 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000357 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000358
359 def start (self, flag=None):
360 self.flag = flag
361 threading.Thread.start(self)
362
363 def run (self):
364 self.sock.settimeout(0.5)
365 self.sock.listen(5)
366 self.active = True
367 if self.flag:
368 # signal an event
369 self.flag.set()
370 while self.active:
371 try:
372 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000373 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000374 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000375 + repr(connaddr) + '\n')
376 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000377 handler.start()
378 except socket.timeout:
379 pass
380 except KeyboardInterrupt:
381 self.stop()
382 except:
383 if self.chatty:
384 handle_error("Test server failure:\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000385 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000386
387 def stop (self):
388 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000389
Bill Janssen54cc54c2007-12-14 22:08:56 +0000390 class OurHTTPSServer(threading.Thread):
391
392 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000393
394 class HTTPSServer(HTTPServer):
395
396 def __init__(self, server_address, RequestHandlerClass, certfile):
397
398 HTTPServer.__init__(self, server_address, RequestHandlerClass)
399 # we assume the certfile contains both private key and certificate
400 self.certfile = certfile
401 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000402 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000403 self.allow_reuse_address = True
404
Bill Janssen6e027db2007-11-15 22:23:56 +0000405 def __str__(self):
406 return ('<%s %s:%s>' %
407 (self.__class__.__name__,
408 self.server_name,
409 self.server_port))
410
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000411 def get_request (self):
412 # override this to wrap socket with SSL
413 sock, addr = self.socket.accept()
414 sslconn = ssl.wrap_socket(sock, server_side=True,
415 certfile=self.certfile)
416 return sslconn, addr
417
418 # The methods overridden below this are mainly so that we
419 # can run it in a thread and be able to stop it from another
420 # You probably wouldn't need them in other uses.
421
422 def server_activate(self):
423 # We want to run this in a thread for testing purposes,
424 # so we override this to set timeout, so that we get
425 # a chance to stop the server
426 self.socket.settimeout(0.5)
427 HTTPServer.server_activate(self)
428
429 def serve_forever(self):
430 # We want this to run in a thread, so we use a slightly
431 # modified version of "forever".
432 self.active = True
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000433 while 1:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000434 try:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000435 # We need to lock while handling the request.
436 # Another thread can close the socket after self.active
437 # has been checked and before the request is handled.
438 # This causes an exception when using the closed socket.
439 with self.active_lock:
440 if not self.active:
441 break
442 self.handle_request()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000443 except socket.timeout:
444 pass
445 except KeyboardInterrupt:
446 self.server_close()
447 return
448 except:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000449 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
450 break
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000451 time.sleep(0.1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000452
453 def server_close(self):
454 # Again, we want this to run in a thread, so we need to override
455 # close to clear the "active" flag, so that serve_forever() will
456 # terminate.
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000457 with self.active_lock:
458 HTTPServer.server_close(self)
459 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000460
461 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
462
463 # need to override translate_path to get a known root,
464 # instead of using os.curdir, since the test could be
465 # run from anywhere
466
467 server_version = "TestHTTPS/1.0"
468
469 root = None
470
471 def translate_path(self, path):
472 """Translate a /-separated PATH to the local filename syntax.
473
474 Components that mean special things to the local file system
475 (e.g. drive or directory names) are ignored. (XXX They should
476 probably be diagnosed.)
477
478 """
479 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000480 path = urllib.parse.urlparse(path)[2]
481 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000482 words = path.split('/')
483 words = filter(None, words)
484 path = self.root
485 for word in words:
486 drive, word = os.path.splitdrive(word)
487 head, word = os.path.split(word)
488 if word in self.root: continue
489 path = os.path.join(path, word)
490 return path
491
492 def log_message(self, format, *args):
493
494 # we override this to suppress logging unless "verbose"
495
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000496 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000497 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
498 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000499 self.server.server_port,
500 self.request.cipher(),
501 self.log_date_time_string(),
502 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000503
504
Trent Nelson78520002008-04-10 20:54:35 +0000505 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000506 self.flag = None
507 self.active = False
508 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000509 self.port = support.find_unused_port()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000510 self.server = self.HTTPSServer(
Trent Nelson78520002008-04-10 20:54:35 +0000511 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Thomas Woutersed03b412007-08-28 21:37:11 +0000512 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000513 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000514
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000515 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000516 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000517
518 def start (self, flag=None):
519 self.flag = flag
520 threading.Thread.start(self)
521
Thomas Woutersed03b412007-08-28 21:37:11 +0000522 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000523 self.active = True
524 if self.flag:
525 self.flag.set()
526 self.server.serve_forever()
527 self.active = False
528
529 def stop (self):
530 self.active = False
531 self.server.server_close()
532
533
Bill Janssen54cc54c2007-12-14 22:08:56 +0000534 class AsyncoreEchoServer(threading.Thread):
535
536 # this one's based on asyncore.dispatcher
537
538 class EchoServer (asyncore.dispatcher):
539
540 class ConnectionHandler (asyncore.dispatcher_with_send):
541
542 def __init__(self, conn, certfile):
543 self.socket = ssl.wrap_socket(conn, server_side=True,
544 certfile=certfile,
545 do_handshake_on_connect=False)
546 asyncore.dispatcher_with_send.__init__(self, self.socket)
547 # now we have to do the handshake
548 # we'll just do it the easy way, and block the connection
549 # till it's finished. If we were doing it right, we'd
550 # do this in multiple calls to handle_read...
551 self.do_handshake(block=True)
552
553 def readable(self):
554 if isinstance(self.socket, ssl.SSLSocket):
555 while self.socket.pending() > 0:
556 self.handle_read_event()
557 return True
558
559 def handle_read(self):
560 data = self.recv(1024)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000561 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000562 sys.stdout.write(" server: read %s from client\n" % repr(data))
563 if not data:
564 self.close()
565 else:
566 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
567
568 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000569 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000570 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000571 sys.stdout.write(" server: closed connection %s\n" % self.socket)
572
573 def handle_error(self):
574 raise
575
576 def __init__(self, port, certfile):
577 self.port = port
578 self.certfile = certfile
579 asyncore.dispatcher.__init__(self)
580 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
581 self.bind(('', port))
582 self.listen(5)
583
584 def handle_accept(self):
585 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000586 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000587 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
588 self.ConnectionHandler(sock_obj, self.certfile)
589
590 def handle_error(self):
591 raise
592
Trent Nelson78520002008-04-10 20:54:35 +0000593 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000594 self.flag = None
595 self.active = False
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000596 self.port = support.find_unused_port()
Trent Nelson78520002008-04-10 20:54:35 +0000597 self.server = self.EchoServer(self.port, certfile)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000598 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000599 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000600
601 def __str__(self):
602 return "<%s %s>" % (self.__class__.__name__, self.server)
603
604 def start (self, flag=None):
605 self.flag = flag
606 threading.Thread.start(self)
607
608 def run (self):
609 self.active = True
610 if self.flag:
611 self.flag.set()
612 while self.active:
613 try:
614 asyncore.loop(1)
615 except:
616 pass
617
618 def stop (self):
619 self.active = False
620 self.server.close()
621
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000622 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000623 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000624 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000625 cacerts=CERTFILE, chatty=False,
626 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000627 flag = threading.Event()
628 server.start(flag)
629 # wait for it to start
630 flag.wait()
631 # try to connect
632 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000633 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000634 s = ssl.wrap_socket(socket.socket(),
635 certfile=certfile,
636 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000637 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000638 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000639 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000640 sys.stdout.write("\nSSLError is %s\n" % x)
Bill Janssenddc56692008-07-17 18:17:20 +0000641 except socket.error as x:
642 if support.verbose:
643 sys.stdout.write("\nsocket.error is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000644 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000645 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000646 "Use of invalid cert should have failed!")
647 finally:
648 server.stop()
649 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000650
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000651 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000652 client_certfile, client_protocol=None,
653 indata="FOO\n",
654 chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000655
Trent Nelson78520002008-04-10 20:54:35 +0000656 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000657 certreqs=certreqs,
658 ssl_version=protocol,
659 cacerts=cacertsfile,
660 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000661 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000662 flag = threading.Event()
663 server.start(flag)
664 # wait for it to start
665 flag.wait()
666 # try to connect
667 if client_protocol is None:
668 client_protocol = protocol
669 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000670 s = ssl.wrap_socket(socket.socket(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000671 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000672 certfile=client_certfile,
673 ca_certs=cacertsfile,
674 cert_reqs=certreqs,
675 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000676 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000677 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000678 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000679 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000680 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000681 else:
682 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000683 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000684 sys.stdout.write(
685 " client: sending %s...\n" % (repr(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000686 s.write(indata.encode('ASCII', 'strict'))
Bill Janssen6e027db2007-11-15 22:23:56 +0000687 outdata = s.read()
688 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000689 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000690 sys.stdout.write(" client: read %s\n" % repr(outdata))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000691 outdata = str(outdata, 'ASCII', 'strict')
Bill Janssen6e027db2007-11-15 22:23:56 +0000692 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000693 raise support.TestFailed(
Bill Janssen6e027db2007-11-15 22:23:56 +0000694 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Trent Nelson6b240cd2008-04-10 20:12:06 +0000695 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
696 repr(indata[:min(len(indata),20)].lower()), len(indata)))
697 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000698 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000699 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000700 sys.stdout.write(" client: closing connection.\n")
701 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000702 finally:
703 server.stop()
704 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000705
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000706 def tryProtocolCombo (server_protocol,
707 client_protocol,
708 expectedToWork,
709 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000710
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000711 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000712 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000713
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000714 if certsreqs == ssl.CERT_NONE:
715 certtype = "CERT_NONE"
716 elif certsreqs == ssl.CERT_OPTIONAL:
717 certtype = "CERT_OPTIONAL"
718 elif certsreqs == ssl.CERT_REQUIRED:
719 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000720 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000721 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
722 sys.stdout.write(formatstr %
723 (ssl.get_protocol_name(client_protocol),
724 ssl.get_protocol_name(server_protocol),
725 certtype))
726 try:
727 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000728 CERTFILE, CERTFILE, client_protocol,
729 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000730 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000731 if expectedToWork:
732 raise
733 else:
734 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000735 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000736 "Client protocol %s succeeded with server protocol %s!"
737 % (ssl.get_protocol_name(client_protocol),
738 ssl.get_protocol_name(server_protocol)))
739
740
Bill Janssen6e027db2007-11-15 22:23:56 +0000741 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000742
Trent Nelson6b240cd2008-04-10 20:12:06 +0000743 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000744
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000745 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000746 sys.stdout.write("\n")
747 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
748 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
749 chatty=True, connectionchatty=True)
750
751 def testReadCert(self):
752
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000753 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000754 sys.stdout.write("\n")
755 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000756 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000757 certreqs=ssl.CERT_NONE,
758 ssl_version=ssl.PROTOCOL_SSLv23,
759 cacerts=CERTFILE,
760 chatty=False)
761 flag = threading.Event()
762 server.start(flag)
763 # wait for it to start
764 flag.wait()
765 # try to connect
766 try:
767 try:
768 s = ssl.wrap_socket(socket.socket(),
769 certfile=CERTFILE,
770 ca_certs=CERTFILE,
771 cert_reqs=ssl.CERT_REQUIRED,
772 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000773 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000774 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000775 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000776 "Unexpected SSL error: " + str(x))
777 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000778 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000779 "Unexpected exception: " + str(x))
780 else:
781 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000782 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000783 "Can't SSL-handshake with test server")
784 cert = s.getpeercert()
785 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000786 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000787 "Can't get peer certificate.")
788 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000789 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000790 sys.stdout.write(pprint.pformat(cert) + '\n')
791 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000792 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000793 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000794 "No subject field in certificate: %s." %
795 pprint.pformat(cert))
796 if ((('organizationName', 'Python Software Foundation'),)
797 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000798 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000799 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000800 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000801 s.close()
802 finally:
803 server.stop()
804 server.join()
805
806 def testNULLcert(self):
807 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
808 "nullcert.pem"))
809 def testMalformedCert(self):
810 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
811 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000812 def testWrongCert(self):
813 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
814 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000815 def testMalformedKey(self):
816 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
817 "badkey.pem"))
818
Trent Nelson6b240cd2008-04-10 20:12:06 +0000819 def testRudeShutdown(self):
820
821 listener_ready = threading.Event()
822 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000823 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000824
825 # `listener` runs in a thread. It opens a socket listening on
826 # PORT, and sits in an accept() until the main thread connects.
827 # Then it rudely closes the socket, and sets Event `listener_gone`
828 # to let the main thread know the socket is gone.
829 def listener():
830 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000831 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000832 s.listen(5)
833 listener_ready.set()
834 s.accept()
835 s = None # reclaim the socket object, which also closes it
836 listener_gone.set()
837
838 def connector():
839 listener_ready.wait()
840 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000841 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000842 listener_gone.wait()
843 try:
844 ssl_sock = ssl.wrap_socket(s)
845 except IOError:
846 pass
847 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000848 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000849 'connecting to closed SSL socket should have failed')
850
851 t = threading.Thread(target=listener)
852 t.start()
853 connector()
854 t.join()
855
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000856 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000857 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000858 sys.stdout.write("\n")
859 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
860 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
861 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
862 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
863 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
864 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
865
866 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000867 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000868 sys.stdout.write("\n")
869 try:
870 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000871 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000872 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000873 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000874 sys.stdout.write(
875 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
876 % str(x))
877 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
878 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
879 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
880
881 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
882 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
883 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
884
885 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
886 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
887 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
888
889 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000890 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000891 sys.stdout.write("\n")
892 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
893 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
894 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
895 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
896 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
897 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
898
899 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000900 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000901 sys.stdout.write("\n")
902 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
903 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
904 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
905 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
906 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
907 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
908
909 def testSTARTTLS (self):
910
Bill Janssen40a0f662008-08-12 16:56:25 +0000911 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000912
Trent Nelson78520002008-04-10 20:54:35 +0000913 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000914 ssl_version=ssl.PROTOCOL_TLSv1,
915 starttls_server=True,
916 chatty=True,
917 connectionchatty=True)
918 flag = threading.Event()
919 server.start(flag)
920 # wait for it to start
921 flag.wait()
922 # try to connect
923 wrapped = False
924 try:
925 try:
926 s = socket.socket()
927 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000928 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000929 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000930 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000931 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000932 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000933 sys.stdout.write("\n")
934 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000935 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000936 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000937 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000938 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000939 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000940 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000941 outdata = conn.read()
942 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000943 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000944 outdata = s.recv(1024)
945 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000946 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000947 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000948 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000949 sys.stdout.write(
950 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000951 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000952 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000953 wrapped = True
Bill Janssen40a0f662008-08-12 16:56:25 +0000954 elif (indata == "ENDTLS" and
955 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
956 if support.verbose:
957 msg = str(outdata, 'ASCII', 'replace')
958 sys.stdout.write(
959 " client: read %s from server, ending TLS...\n"
960 % repr(msg))
961 s = conn.unwrap()
962 wrapped = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000963 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000964 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000965 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000966 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000967 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000968 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000969 sys.stdout.write(" client: closing connection.\n")
970 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000971 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000972 else:
Bill Janssen40a0f662008-08-12 16:56:25 +0000973 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000974 if wrapped:
975 conn.close()
976 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000977 s.close()
978 finally:
979 server.stop()
980 server.join()
981
Bill Janssen54cc54c2007-12-14 22:08:56 +0000982 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000983
Trent Nelson78520002008-04-10 20:54:35 +0000984 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000985 flag = threading.Event()
986 server.start(flag)
987 # wait for it to start
988 flag.wait()
989 # try to connect
990 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000991 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000992 sys.stdout.write('\n')
993 d1 = open(CERTFILE, 'rb').read()
994 d2 = ''
995 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +0000996 url = 'https://%s:%d/%s' % (
997 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000998 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +0000999 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001000 if dlen and (int(dlen) > 0):
1001 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001002 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001003 sys.stdout.write(
1004 " client: read %d bytes from remote server '%s'\n"
1005 % (len(d2), server))
1006 f.close()
1007 except:
1008 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001009 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001010 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001011 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001012 else:
1013 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +00001014 print("d1 is", len(d1), repr(d1))
1015 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001016 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001017 "Couldn't fetch data from HTTPS server")
1018 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001019 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001020 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001021 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001022 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001023 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001024 server.join()
1025
Trent Nelson6b240cd2008-04-10 20:12:06 +00001026 def testAsyncoreServer(self):
1027
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001028 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001029 sys.stdout.write("\n")
1030
1031 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001032 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001033 flag = threading.Event()
1034 server.start(flag)
1035 # wait for it to start
1036 flag.wait()
1037 # try to connect
1038 try:
1039 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +00001040 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001041 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001042 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001043 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001044 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001045 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001046 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001047 sys.stdout.write(
1048 " client: sending %s...\n" % (repr(indata)))
1049 s.sendall(indata.encode('ASCII', 'strict'))
1050 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001051 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001052 sys.stdout.write(" client: read %s\n" % repr(outdata))
1053 outdata = str(outdata, 'ASCII', 'strict')
1054 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001055 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001056 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1057 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1058 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1059 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001060 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001061 sys.stdout.write(" client: closing connection.\n")
1062 s.close()
1063 finally:
1064 server.stop()
1065 server.join()
1066
Bill Janssen58afe4c2008-09-08 16:45:19 +00001067 def testAllRecvAndSendMethods(self):
1068
1069 if support.verbose:
1070 sys.stdout.write("\n")
1071
1072 server = ThreadedEchoServer(CERTFILE,
1073 certreqs=ssl.CERT_NONE,
1074 ssl_version=ssl.PROTOCOL_TLSv1,
1075 cacerts=CERTFILE,
1076 chatty=True,
1077 connectionchatty=False)
1078 flag = threading.Event()
1079 server.start(flag)
1080 # wait for it to start
1081 flag.wait()
1082 # try to connect
1083 try:
1084 s = ssl.wrap_socket(socket.socket(),
1085 server_side=False,
1086 certfile=CERTFILE,
1087 ca_certs=CERTFILE,
1088 cert_reqs=ssl.CERT_NONE,
1089 ssl_version=ssl.PROTOCOL_TLSv1)
1090 s.connect((HOST, server.port))
1091 except ssl.SSLError as x:
1092 raise support.TestFailed("Unexpected SSL error: " + str(x))
1093 except Exception as x:
1094 raise support.TestFailed("Unexpected exception: " + str(x))
1095 else:
1096 # helper methods for standardising recv* method signatures
1097 def _recv_into():
1098 b = bytearray(b"\0"*100)
1099 count = s.recv_into(b)
1100 return b[:count]
1101
1102 def _recvfrom_into():
1103 b = bytearray(b"\0"*100)
1104 count, addr = s.recvfrom_into(b)
1105 return b[:count]
1106
1107 # (name, method, whether to expect success, *args)
1108 send_methods = [
1109 ('send', s.send, True, []),
1110 ('sendto', s.sendto, False, ["some.address"]),
1111 ('sendall', s.sendall, True, []),
1112 ]
1113 recv_methods = [
1114 ('recv', s.recv, True, []),
1115 ('recvfrom', s.recvfrom, False, ["some.address"]),
1116 ('recv_into', _recv_into, True, []),
1117 ('recvfrom_into', _recvfrom_into, False, []),
1118 ]
1119 data_prefix = "PREFIX_"
1120
1121 for meth_name, send_meth, expect_success, args in send_methods:
1122 indata = data_prefix + meth_name
1123 try:
1124 send_meth(indata.encode('ASCII', 'strict'), *args)
1125 outdata = s.read()
1126 outdata = str(outdata, 'ASCII', 'strict')
1127 if outdata != indata.lower():
1128 raise support.TestFailed(
1129 "While sending with <<{name:s}>> bad data "
1130 "<<{outdata:s}>> ({nout:d}) received; "
1131 "expected <<{indata:s}>> ({nin:d})\n".format(
1132 name=meth_name, outdata=repr(outdata[:20]),
1133 nout=len(outdata),
1134 indata=repr(indata[:20]), nin=len(indata)
1135 )
1136 )
1137 except ValueError as e:
1138 if expect_success:
1139 raise support.TestFailed(
1140 "Failed to send with method <<{name:s}>>; "
1141 "expected to succeed.\n".format(name=meth_name)
1142 )
1143 if not str(e).startswith(meth_name):
1144 raise support.TestFailed(
1145 "Method <<{name:s}>> failed with unexpected "
1146 "exception message: {exp:s}\n".format(
1147 name=meth_name, exp=e
1148 )
1149 )
1150
1151 for meth_name, recv_meth, expect_success, args in recv_methods:
1152 indata = data_prefix + meth_name
1153 try:
1154 s.send(indata.encode('ASCII', 'strict'))
1155 outdata = recv_meth(*args)
1156 outdata = str(outdata, 'ASCII', 'strict')
1157 if outdata != indata.lower():
1158 raise support.TestFailed(
1159 "While receiving with <<{name:s}>> bad data "
1160 "<<{outdata:s}>> ({nout:d}) received; "
1161 "expected <<{indata:s}>> ({nin:d})\n".format(
1162 name=meth_name, outdata=repr(outdata[:20]),
1163 nout=len(outdata),
1164 indata=repr(indata[:20]), nin=len(indata)
1165 )
1166 )
1167 except ValueError as e:
1168 if expect_success:
1169 raise support.TestFailed(
1170 "Failed to receive with method <<{name:s}>>; "
1171 "expected to succeed.\n".format(name=meth_name)
1172 )
1173 if not str(e).startswith(meth_name):
1174 raise support.TestFailed(
1175 "Method <<{name:s}>> failed with unexpected "
1176 "exception message: {exp:s}\n".format(
1177 name=meth_name, exp=e
1178 )
1179 )
1180 # consume data
1181 s.read()
1182
1183 s.write("over\n".encode("ASCII", "strict"))
1184 s.close()
1185 finally:
1186 server.stop()
1187 server.join()
1188
1189
Thomas Woutersed03b412007-08-28 21:37:11 +00001190def test_main(verbose=False):
1191 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001192 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001193
Trent Nelson78520002008-04-10 20:54:35 +00001194 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001195 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1196 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001197 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1198 os.path.dirname(__file__) or os.curdir,
1199 "https_svn_python_org_root.pem")
1200
1201 if (not os.path.exists(CERTFILE) or
1202 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001203 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001204
Thomas Woutersed03b412007-08-28 21:37:11 +00001205 tests = [BasicTests]
1206
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001207 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001208 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001209
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001210 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001211 thread_info = support.threading_setup()
1212 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001213 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001214
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001215 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001216
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001217 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001218 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001219
1220if __name__ == "__main__":
1221 test_main()