blob: 15af33343ec675235d19bdda841fdf79b8ddb330 [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 Pitrouda6902c2010-04-21 19:52:52 +0000179 def test_algorithms(self):
180 # Issue #8484: all algorithms should be available when verifying a
181 # certificate.
182 # NOTE: https://sha256.tbs-internet.com is another possible test host
183 remote = ("sha2.hboeck.de", 443)
184 sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
185 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
186 cert_reqs=ssl.CERT_REQUIRED,
187 ca_certs=sha256_cert,)
188 with support.transient_internet():
189 try:
190 s.connect(remote)
191 if support.verbose:
192 sys.stdout.write("\nCipher with %r is %r\n" %
193 (remote, s.cipher()))
194 sys.stdout.write("Certificate is:\n%s\n" %
195 pprint.pformat(s.getpeercert()))
196 finally:
197 s.close()
198
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000199
200try:
201 import threading
202except ImportError:
203 _have_threads = False
204else:
205
206 _have_threads = True
207
208 class ThreadedEchoServer(threading.Thread):
209
210 class ConnectionHandler(threading.Thread):
211
212 """A mildly complicated class, because we want it to work both
213 with and without the SSL wrapper around the socket connection, so
214 that we can test the STARTTLS functionality."""
215
Bill Janssen6e027db2007-11-15 22:23:56 +0000216 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000217 self.server = server
218 self.running = False
219 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000220 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000221 self.sock.setblocking(1)
222 self.sslconn = None
223 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000224 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000225
226 def wrap_conn (self):
227 try:
228 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
229 certfile=self.server.certificate,
230 ssl_version=self.server.protocol,
231 ca_certs=self.server.cacerts,
232 cert_reqs=self.server.certreqs)
233 except:
234 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000235 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000236 if not self.server.expect_bad_connects:
237 # here, we want to stop the server, because this shouldn't
238 # happen in the context of our test case
239 self.running = False
240 # normally, we'd just stop here, but for the test
241 # harness, we want to stop the server
242 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000243 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000244 return False
245
246 else:
247 if self.server.certreqs == ssl.CERT_REQUIRED:
248 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000249 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000250 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
251 cert_binary = self.sslconn.getpeercert(True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000252 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000253 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
254 cipher = self.sslconn.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000255 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000256 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
257 return True
258
259 def read(self):
260 if self.sslconn:
261 return self.sslconn.read()
262 else:
263 return self.sock.recv(1024)
264
265 def write(self, bytes):
266 if self.sslconn:
267 return self.sslconn.write(bytes)
268 else:
269 return self.sock.send(bytes)
270
271 def close(self):
272 if self.sslconn:
273 self.sslconn.close()
274 else:
275 self.sock.close()
276
277 def run (self):
278 self.running = True
279 if not self.server.starttls_server:
280 if not self.wrap_conn():
281 return
282 while self.running:
283 try:
284 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000285 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000286 if not msg:
287 # eof, so quit this handler
288 self.running = False
289 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000290 elif amsg.strip() == 'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000291 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000292 sys.stdout.write(" server: client closed connection\n")
293 self.close()
294 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000295 elif (self.server.starttls_server and
296 amsg.strip() == 'STARTTLS'):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000297 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000298 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000299 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000300 if not self.wrap_conn():
301 return
Bill Janssen40a0f662008-08-12 16:56:25 +0000302 elif (self.server.starttls_server and self.sslconn
303 and amsg.strip() == 'ENDTLS'):
304 if support.verbose and self.server.connectionchatty:
305 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
306 self.write("OK\n".encode("ASCII", "strict"))
307 self.sock = self.sslconn.unwrap()
308 self.sslconn = None
309 if support.verbose and self.server.connectionchatty:
310 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000311 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000312 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000313 self.server.connectionchatty):
314 ctype = (self.sslconn and "encrypted") or "unencrypted"
315 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
316 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000317 self.write(amsg.lower().encode('ASCII', 'strict'))
318 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000319 if self.server.chatty:
320 handle_error("Test server failure:\n")
321 self.close()
322 self.running = False
323 # normally, we'd just stop here, but for the test
324 # harness, we want to stop the server
325 self.server.stop()
326 except:
327 handle_error('')
328
Trent Nelson78520002008-04-10 20:54:35 +0000329 def __init__(self, certificate, ssl_version=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000330 certreqs=None, cacerts=None, expect_bad_connects=False,
331 chatty=True, connectionchatty=False, starttls_server=False):
332 if ssl_version is None:
333 ssl_version = ssl.PROTOCOL_TLSv1
334 if certreqs is None:
335 certreqs = ssl.CERT_NONE
336 self.certificate = certificate
337 self.protocol = ssl_version
338 self.certreqs = certreqs
339 self.cacerts = cacerts
340 self.expect_bad_connects = expect_bad_connects
341 self.chatty = chatty
342 self.connectionchatty = connectionchatty
343 self.starttls_server = starttls_server
344 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000345 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000346 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000347 self.active = False
348 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000349 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000350
351 def start (self, flag=None):
352 self.flag = flag
353 threading.Thread.start(self)
354
355 def run (self):
356 self.sock.settimeout(0.5)
357 self.sock.listen(5)
358 self.active = True
359 if self.flag:
360 # signal an event
361 self.flag.set()
362 while self.active:
363 try:
364 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000365 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000366 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000367 + repr(connaddr) + '\n')
368 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000369 handler.start()
370 except socket.timeout:
371 pass
372 except KeyboardInterrupt:
373 self.stop()
374 except:
375 if self.chatty:
376 handle_error("Test server failure:\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000377 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000378
379 def stop (self):
380 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000381
Bill Janssen54cc54c2007-12-14 22:08:56 +0000382 class OurHTTPSServer(threading.Thread):
383
384 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000385
386 class HTTPSServer(HTTPServer):
387
388 def __init__(self, server_address, RequestHandlerClass, certfile):
389
390 HTTPServer.__init__(self, server_address, RequestHandlerClass)
391 # we assume the certfile contains both private key and certificate
392 self.certfile = certfile
393 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000394 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000395 self.allow_reuse_address = True
396
Bill Janssen6e027db2007-11-15 22:23:56 +0000397 def __str__(self):
398 return ('<%s %s:%s>' %
399 (self.__class__.__name__,
400 self.server_name,
401 self.server_port))
402
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000403 def get_request (self):
404 # override this to wrap socket with SSL
405 sock, addr = self.socket.accept()
406 sslconn = ssl.wrap_socket(sock, server_side=True,
407 certfile=self.certfile)
408 return sslconn, addr
409
410 # The methods overridden below this are mainly so that we
411 # can run it in a thread and be able to stop it from another
412 # You probably wouldn't need them in other uses.
413
414 def server_activate(self):
415 # We want to run this in a thread for testing purposes,
416 # so we override this to set timeout, so that we get
417 # a chance to stop the server
418 self.socket.settimeout(0.5)
419 HTTPServer.server_activate(self)
420
421 def serve_forever(self):
422 # We want this to run in a thread, so we use a slightly
423 # modified version of "forever".
424 self.active = True
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000425 while 1:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000426 try:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000427 # We need to lock while handling the request.
428 # Another thread can close the socket after self.active
429 # has been checked and before the request is handled.
430 # This causes an exception when using the closed socket.
431 with self.active_lock:
432 if not self.active:
433 break
434 self.handle_request()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000435 except socket.timeout:
436 pass
437 except KeyboardInterrupt:
438 self.server_close()
439 return
440 except:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000441 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
442 break
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000443 time.sleep(0.1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000444
445 def server_close(self):
446 # Again, we want this to run in a thread, so we need to override
447 # close to clear the "active" flag, so that serve_forever() will
448 # terminate.
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000449 with self.active_lock:
450 HTTPServer.server_close(self)
451 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000452
453 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
454
455 # need to override translate_path to get a known root,
456 # instead of using os.curdir, since the test could be
457 # run from anywhere
458
459 server_version = "TestHTTPS/1.0"
460
461 root = None
462
463 def translate_path(self, path):
464 """Translate a /-separated PATH to the local filename syntax.
465
466 Components that mean special things to the local file system
467 (e.g. drive or directory names) are ignored. (XXX They should
468 probably be diagnosed.)
469
470 """
471 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000472 path = urllib.parse.urlparse(path)[2]
473 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000474 words = path.split('/')
475 words = filter(None, words)
476 path = self.root
477 for word in words:
478 drive, word = os.path.splitdrive(word)
479 head, word = os.path.split(word)
480 if word in self.root: continue
481 path = os.path.join(path, word)
482 return path
483
484 def log_message(self, format, *args):
485
486 # we override this to suppress logging unless "verbose"
487
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000488 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000489 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
490 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000491 self.server.server_port,
492 self.request.cipher(),
493 self.log_date_time_string(),
494 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000495
496
Trent Nelson78520002008-04-10 20:54:35 +0000497 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000498 self.flag = None
499 self.active = False
500 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000501 self.port = support.find_unused_port()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000502 self.server = self.HTTPSServer(
Trent Nelson78520002008-04-10 20:54:35 +0000503 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Thomas Woutersed03b412007-08-28 21:37:11 +0000504 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000505 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000506
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000507 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000508 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000509
510 def start (self, flag=None):
511 self.flag = flag
512 threading.Thread.start(self)
513
Thomas Woutersed03b412007-08-28 21:37:11 +0000514 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000515 self.active = True
516 if self.flag:
517 self.flag.set()
518 self.server.serve_forever()
519 self.active = False
520
521 def stop (self):
522 self.active = False
523 self.server.server_close()
524
525
Bill Janssen54cc54c2007-12-14 22:08:56 +0000526 class AsyncoreEchoServer(threading.Thread):
527
528 # this one's based on asyncore.dispatcher
529
530 class EchoServer (asyncore.dispatcher):
531
532 class ConnectionHandler (asyncore.dispatcher_with_send):
533
534 def __init__(self, conn, certfile):
535 self.socket = ssl.wrap_socket(conn, server_side=True,
536 certfile=certfile,
537 do_handshake_on_connect=False)
538 asyncore.dispatcher_with_send.__init__(self, self.socket)
539 # now we have to do the handshake
540 # we'll just do it the easy way, and block the connection
541 # till it's finished. If we were doing it right, we'd
542 # do this in multiple calls to handle_read...
543 self.do_handshake(block=True)
544
545 def readable(self):
546 if isinstance(self.socket, ssl.SSLSocket):
547 while self.socket.pending() > 0:
548 self.handle_read_event()
549 return True
550
551 def handle_read(self):
552 data = self.recv(1024)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000553 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000554 sys.stdout.write(" server: read %s from client\n" % repr(data))
555 if not data:
556 self.close()
557 else:
558 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
559
560 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000561 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000562 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000563 sys.stdout.write(" server: closed connection %s\n" % self.socket)
564
565 def handle_error(self):
566 raise
567
568 def __init__(self, port, certfile):
569 self.port = port
570 self.certfile = certfile
571 asyncore.dispatcher.__init__(self)
572 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
573 self.bind(('', port))
574 self.listen(5)
575
576 def handle_accept(self):
577 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000578 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000579 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
580 self.ConnectionHandler(sock_obj, self.certfile)
581
582 def handle_error(self):
583 raise
584
Trent Nelson78520002008-04-10 20:54:35 +0000585 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000586 self.flag = None
587 self.active = False
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000588 self.port = support.find_unused_port()
Trent Nelson78520002008-04-10 20:54:35 +0000589 self.server = self.EchoServer(self.port, certfile)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000590 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000591 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000592
593 def __str__(self):
594 return "<%s %s>" % (self.__class__.__name__, self.server)
595
596 def start (self, flag=None):
597 self.flag = flag
598 threading.Thread.start(self)
599
600 def run (self):
601 self.active = True
602 if self.flag:
603 self.flag.set()
604 while self.active:
605 try:
606 asyncore.loop(1)
607 except:
608 pass
609
610 def stop (self):
611 self.active = False
612 self.server.close()
613
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000614 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000615 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000616 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000617 cacerts=CERTFILE, chatty=False,
618 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000619 flag = threading.Event()
620 server.start(flag)
621 # wait for it to start
622 flag.wait()
623 # try to connect
624 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000625 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000626 s = ssl.wrap_socket(socket.socket(),
627 certfile=certfile,
628 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000629 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000630 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000631 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000632 sys.stdout.write("\nSSLError is %s\n" % x)
Bill Janssenddc56692008-07-17 18:17:20 +0000633 except socket.error as x:
634 if support.verbose:
635 sys.stdout.write("\nsocket.error is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000636 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000637 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000638 "Use of invalid cert should have failed!")
639 finally:
640 server.stop()
641 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000642
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000643 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000644 client_certfile, client_protocol=None,
645 indata="FOO\n",
646 chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000647
Trent Nelson78520002008-04-10 20:54:35 +0000648 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000649 certreqs=certreqs,
650 ssl_version=protocol,
651 cacerts=cacertsfile,
652 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000653 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000654 flag = threading.Event()
655 server.start(flag)
656 # wait for it to start
657 flag.wait()
658 # try to connect
659 if client_protocol is None:
660 client_protocol = protocol
661 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000662 s = ssl.wrap_socket(socket.socket(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000663 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000664 certfile=client_certfile,
665 ca_certs=cacertsfile,
666 cert_reqs=certreqs,
667 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000668 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000669 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000670 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000671 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000672 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000673 else:
674 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000675 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000676 sys.stdout.write(
677 " client: sending %s...\n" % (repr(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000678 s.write(indata.encode('ASCII', 'strict'))
Bill Janssen6e027db2007-11-15 22:23:56 +0000679 outdata = s.read()
680 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000681 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000682 sys.stdout.write(" client: read %s\n" % repr(outdata))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000683 outdata = str(outdata, 'ASCII', 'strict')
Bill Janssen6e027db2007-11-15 22:23:56 +0000684 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000685 raise support.TestFailed(
Bill Janssen6e027db2007-11-15 22:23:56 +0000686 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Trent Nelson6b240cd2008-04-10 20:12:06 +0000687 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
688 repr(indata[:min(len(indata),20)].lower()), len(indata)))
689 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000690 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000691 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000692 sys.stdout.write(" client: closing connection.\n")
693 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000694 finally:
695 server.stop()
696 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000697
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000698 def tryProtocolCombo (server_protocol,
699 client_protocol,
700 expectedToWork,
701 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000702
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000703 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000704 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000705
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000706 if certsreqs == ssl.CERT_NONE:
707 certtype = "CERT_NONE"
708 elif certsreqs == ssl.CERT_OPTIONAL:
709 certtype = "CERT_OPTIONAL"
710 elif certsreqs == ssl.CERT_REQUIRED:
711 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000712 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000713 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
714 sys.stdout.write(formatstr %
715 (ssl.get_protocol_name(client_protocol),
716 ssl.get_protocol_name(server_protocol),
717 certtype))
718 try:
719 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000720 CERTFILE, CERTFILE, client_protocol,
721 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000722 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000723 if expectedToWork:
724 raise
725 else:
726 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000727 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000728 "Client protocol %s succeeded with server protocol %s!"
729 % (ssl.get_protocol_name(client_protocol),
730 ssl.get_protocol_name(server_protocol)))
731
732
Bill Janssen6e027db2007-11-15 22:23:56 +0000733 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000734
Trent Nelson6b240cd2008-04-10 20:12:06 +0000735 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000736
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000737 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000738 sys.stdout.write("\n")
739 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
740 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
741 chatty=True, connectionchatty=True)
742
743 def testReadCert(self):
744
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000745 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000746 sys.stdout.write("\n")
747 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000748 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000749 certreqs=ssl.CERT_NONE,
750 ssl_version=ssl.PROTOCOL_SSLv23,
751 cacerts=CERTFILE,
752 chatty=False)
753 flag = threading.Event()
754 server.start(flag)
755 # wait for it to start
756 flag.wait()
757 # try to connect
758 try:
759 try:
760 s = ssl.wrap_socket(socket.socket(),
761 certfile=CERTFILE,
762 ca_certs=CERTFILE,
763 cert_reqs=ssl.CERT_REQUIRED,
764 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000765 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000766 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000767 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000768 "Unexpected SSL error: " + str(x))
769 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000770 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000771 "Unexpected exception: " + str(x))
772 else:
773 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000774 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000775 "Can't SSL-handshake with test server")
776 cert = s.getpeercert()
777 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000778 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000779 "Can't get peer certificate.")
780 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000781 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000782 sys.stdout.write(pprint.pformat(cert) + '\n')
783 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000784 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000785 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000786 "No subject field in certificate: %s." %
787 pprint.pformat(cert))
788 if ((('organizationName', 'Python Software Foundation'),)
789 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000790 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000791 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000792 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000793 s.close()
794 finally:
795 server.stop()
796 server.join()
797
798 def testNULLcert(self):
799 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
800 "nullcert.pem"))
801 def testMalformedCert(self):
802 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
803 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000804 def testWrongCert(self):
805 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
806 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000807 def testMalformedKey(self):
808 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
809 "badkey.pem"))
810
Trent Nelson6b240cd2008-04-10 20:12:06 +0000811 def testRudeShutdown(self):
812
813 listener_ready = threading.Event()
814 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000815 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000816
817 # `listener` runs in a thread. It opens a socket listening on
818 # PORT, and sits in an accept() until the main thread connects.
819 # Then it rudely closes the socket, and sets Event `listener_gone`
820 # to let the main thread know the socket is gone.
821 def listener():
822 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000823 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000824 s.listen(5)
825 listener_ready.set()
826 s.accept()
827 s = None # reclaim the socket object, which also closes it
828 listener_gone.set()
829
830 def connector():
831 listener_ready.wait()
832 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000833 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000834 listener_gone.wait()
835 try:
836 ssl_sock = ssl.wrap_socket(s)
837 except IOError:
838 pass
839 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000840 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000841 'connecting to closed SSL socket should have failed')
842
843 t = threading.Thread(target=listener)
844 t.start()
845 connector()
846 t.join()
847
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000848 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000849 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000850 sys.stdout.write("\n")
851 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
852 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
853 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
854 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
855 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
856 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
857
858 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000859 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000860 sys.stdout.write("\n")
861 try:
862 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000863 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000864 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000865 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000866 sys.stdout.write(
867 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
868 % str(x))
869 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
870 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
871 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
872
873 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
874 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
875 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
876
877 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
878 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
879 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
880
881 def testProtocolSSL3(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_SSLv3, ssl.PROTOCOL_SSLv3, True)
885 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
886 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
887 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
888 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
889 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
890
891 def testProtocolTLS1(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 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
895 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
896 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
897 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
898 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
899 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
900
901 def testSTARTTLS (self):
902
Bill Janssen40a0f662008-08-12 16:56:25 +0000903 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000904
Trent Nelson78520002008-04-10 20:54:35 +0000905 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000906 ssl_version=ssl.PROTOCOL_TLSv1,
907 starttls_server=True,
908 chatty=True,
909 connectionchatty=True)
910 flag = threading.Event()
911 server.start(flag)
912 # wait for it to start
913 flag.wait()
914 # try to connect
915 wrapped = False
916 try:
917 try:
918 s = socket.socket()
919 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000920 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000921 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000922 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000923 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000924 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000925 sys.stdout.write("\n")
926 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000927 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000928 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000929 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000930 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000931 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000932 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000933 outdata = conn.read()
934 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000935 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000936 outdata = s.recv(1024)
937 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000938 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000939 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000940 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000941 sys.stdout.write(
942 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000943 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000944 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000945 wrapped = True
Bill Janssen40a0f662008-08-12 16:56:25 +0000946 elif (indata == "ENDTLS" and
947 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
948 if support.verbose:
949 msg = str(outdata, 'ASCII', 'replace')
950 sys.stdout.write(
951 " client: read %s from server, ending TLS...\n"
952 % repr(msg))
953 s = conn.unwrap()
954 wrapped = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000955 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000956 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000957 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000958 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000959 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000960 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000961 sys.stdout.write(" client: closing connection.\n")
962 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000963 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000964 else:
Bill Janssen40a0f662008-08-12 16:56:25 +0000965 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000966 if wrapped:
967 conn.close()
968 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000969 s.close()
970 finally:
971 server.stop()
972 server.join()
973
Bill Janssen54cc54c2007-12-14 22:08:56 +0000974 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000975
Trent Nelson78520002008-04-10 20:54:35 +0000976 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000977 flag = threading.Event()
978 server.start(flag)
979 # wait for it to start
980 flag.wait()
981 # try to connect
982 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000983 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000984 sys.stdout.write('\n')
985 d1 = open(CERTFILE, 'rb').read()
986 d2 = ''
987 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +0000988 url = 'https://%s:%d/%s' % (
989 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000990 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +0000991 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000992 if dlen and (int(dlen) > 0):
993 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000994 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000995 sys.stdout.write(
996 " client: read %d bytes from remote server '%s'\n"
997 % (len(d2), server))
998 f.close()
999 except:
1000 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001001 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001002 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001003 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001004 else:
1005 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +00001006 print("d1 is", len(d1), repr(d1))
1007 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001008 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001009 "Couldn't fetch data from HTTPS server")
1010 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001011 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001012 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001013 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001014 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001015 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001016 server.join()
1017
Trent Nelson6b240cd2008-04-10 20:12:06 +00001018 def testAsyncoreServer(self):
1019
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001020 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001021 sys.stdout.write("\n")
1022
1023 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001024 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001025 flag = threading.Event()
1026 server.start(flag)
1027 # wait for it to start
1028 flag.wait()
1029 # try to connect
1030 try:
1031 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +00001032 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001033 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001034 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001035 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001036 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001037 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001038 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001039 sys.stdout.write(
1040 " client: sending %s...\n" % (repr(indata)))
1041 s.sendall(indata.encode('ASCII', 'strict'))
1042 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001043 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001044 sys.stdout.write(" client: read %s\n" % repr(outdata))
1045 outdata = str(outdata, 'ASCII', 'strict')
1046 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001047 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001048 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1049 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1050 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1051 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001052 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001053 sys.stdout.write(" client: closing connection.\n")
1054 s.close()
1055 finally:
1056 server.stop()
1057 server.join()
1058
Bill Janssen58afe4c2008-09-08 16:45:19 +00001059 def testAllRecvAndSendMethods(self):
1060
1061 if support.verbose:
1062 sys.stdout.write("\n")
1063
1064 server = ThreadedEchoServer(CERTFILE,
1065 certreqs=ssl.CERT_NONE,
1066 ssl_version=ssl.PROTOCOL_TLSv1,
1067 cacerts=CERTFILE,
1068 chatty=True,
1069 connectionchatty=False)
1070 flag = threading.Event()
1071 server.start(flag)
1072 # wait for it to start
1073 flag.wait()
1074 # try to connect
1075 try:
1076 s = ssl.wrap_socket(socket.socket(),
1077 server_side=False,
1078 certfile=CERTFILE,
1079 ca_certs=CERTFILE,
1080 cert_reqs=ssl.CERT_NONE,
1081 ssl_version=ssl.PROTOCOL_TLSv1)
1082 s.connect((HOST, server.port))
1083 except ssl.SSLError as x:
1084 raise support.TestFailed("Unexpected SSL error: " + str(x))
1085 except Exception as x:
1086 raise support.TestFailed("Unexpected exception: " + str(x))
1087 else:
1088 # helper methods for standardising recv* method signatures
1089 def _recv_into():
1090 b = bytearray(b"\0"*100)
1091 count = s.recv_into(b)
1092 return b[:count]
1093
1094 def _recvfrom_into():
1095 b = bytearray(b"\0"*100)
1096 count, addr = s.recvfrom_into(b)
1097 return b[:count]
1098
1099 # (name, method, whether to expect success, *args)
1100 send_methods = [
1101 ('send', s.send, True, []),
1102 ('sendto', s.sendto, False, ["some.address"]),
1103 ('sendall', s.sendall, True, []),
1104 ]
1105 recv_methods = [
1106 ('recv', s.recv, True, []),
1107 ('recvfrom', s.recvfrom, False, ["some.address"]),
1108 ('recv_into', _recv_into, True, []),
1109 ('recvfrom_into', _recvfrom_into, False, []),
1110 ]
1111 data_prefix = "PREFIX_"
1112
1113 for meth_name, send_meth, expect_success, args in send_methods:
1114 indata = data_prefix + meth_name
1115 try:
1116 send_meth(indata.encode('ASCII', 'strict'), *args)
1117 outdata = s.read()
1118 outdata = str(outdata, 'ASCII', 'strict')
1119 if outdata != indata.lower():
1120 raise support.TestFailed(
1121 "While sending with <<{name:s}>> bad data "
1122 "<<{outdata:s}>> ({nout:d}) received; "
1123 "expected <<{indata:s}>> ({nin:d})\n".format(
1124 name=meth_name, outdata=repr(outdata[:20]),
1125 nout=len(outdata),
1126 indata=repr(indata[:20]), nin=len(indata)
1127 )
1128 )
1129 except ValueError as e:
1130 if expect_success:
1131 raise support.TestFailed(
1132 "Failed to send with method <<{name:s}>>; "
1133 "expected to succeed.\n".format(name=meth_name)
1134 )
1135 if not str(e).startswith(meth_name):
1136 raise support.TestFailed(
1137 "Method <<{name:s}>> failed with unexpected "
1138 "exception message: {exp:s}\n".format(
1139 name=meth_name, exp=e
1140 )
1141 )
1142
1143 for meth_name, recv_meth, expect_success, args in recv_methods:
1144 indata = data_prefix + meth_name
1145 try:
1146 s.send(indata.encode('ASCII', 'strict'))
1147 outdata = recv_meth(*args)
1148 outdata = str(outdata, 'ASCII', 'strict')
1149 if outdata != indata.lower():
1150 raise support.TestFailed(
1151 "While receiving with <<{name:s}>> bad data "
1152 "<<{outdata:s}>> ({nout:d}) received; "
1153 "expected <<{indata:s}>> ({nin:d})\n".format(
1154 name=meth_name, outdata=repr(outdata[:20]),
1155 nout=len(outdata),
1156 indata=repr(indata[:20]), nin=len(indata)
1157 )
1158 )
1159 except ValueError as e:
1160 if expect_success:
1161 raise support.TestFailed(
1162 "Failed to receive with method <<{name:s}>>; "
1163 "expected to succeed.\n".format(name=meth_name)
1164 )
1165 if not str(e).startswith(meth_name):
1166 raise support.TestFailed(
1167 "Method <<{name:s}>> failed with unexpected "
1168 "exception message: {exp:s}\n".format(
1169 name=meth_name, exp=e
1170 )
1171 )
1172 # consume data
1173 s.read()
1174
1175 s.write("over\n".encode("ASCII", "strict"))
1176 s.close()
1177 finally:
1178 server.stop()
1179 server.join()
1180
1181
Thomas Woutersed03b412007-08-28 21:37:11 +00001182def test_main(verbose=False):
1183 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001184 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001185
Trent Nelson78520002008-04-10 20:54:35 +00001186 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001187 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1188 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001189 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1190 os.path.dirname(__file__) or os.curdir,
1191 "https_svn_python_org_root.pem")
1192
1193 if (not os.path.exists(CERTFILE) or
1194 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001195 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001196
Thomas Woutersed03b412007-08-28 21:37:11 +00001197 tests = [BasicTests]
1198
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001199 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001200 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001201
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001202 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001203 thread_info = support.threading_setup()
1204 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001205 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001206
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001207 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001208
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001209 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001210 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001211
1212if __name__ == "__main__":
1213 test_main()