PageRenderTime 74ms CodeModel.GetById 39ms RepoModel.GetById 0ms app.codeStats 1ms

/lib-python/2.7/test/test_ssl.py

https://bitbucket.org/santa4nt/jython
Python | 1394 lines | 1214 code | 97 blank | 83 comment | 193 complexity | f298d7daef41c2de6b3313fd7c0d50e5 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. # Test the support for SSL and sockets
  2. import sys
  3. import unittest
  4. from test import test_support
  5. import asyncore
  6. import socket
  7. import select
  8. import time
  9. import gc
  10. import os
  11. import errno
  12. import pprint
  13. import urllib, urlparse
  14. import traceback
  15. import weakref
  16. import functools
  17. import platform
  18. from BaseHTTPServer import HTTPServer
  19. from SimpleHTTPServer import SimpleHTTPRequestHandler
  20. ssl = test_support.import_module("ssl")
  21. HOST = test_support.HOST
  22. CERTFILE = None
  23. SVN_PYTHON_ORG_ROOT_CERT = None
  24. def handle_error(prefix):
  25. exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
  26. if test_support.verbose:
  27. sys.stdout.write(prefix + exc_format)
  28. class BasicTests(unittest.TestCase):
  29. def test_sslwrap_simple(self):
  30. # A crude test for the legacy API
  31. try:
  32. ssl.sslwrap_simple(socket.socket(socket.AF_INET))
  33. except IOError, e:
  34. if e.errno == 32: # broken pipe when ssl_sock.do_handshake(), this test doesn't care about that
  35. pass
  36. else:
  37. raise
  38. try:
  39. ssl.sslwrap_simple(socket.socket(socket.AF_INET)._sock)
  40. except IOError, e:
  41. if e.errno == 32: # broken pipe when ssl_sock.do_handshake(), this test doesn't care about that
  42. pass
  43. else:
  44. raise
  45. # Issue #9415: Ubuntu hijacks their OpenSSL and forcefully disables SSLv2
  46. def skip_if_broken_ubuntu_ssl(func):
  47. if hasattr(ssl, 'PROTOCOL_SSLv2'):
  48. # We need to access the lower-level wrapper in order to create an
  49. # implicit SSL context without trying to connect or listen.
  50. try:
  51. import _ssl
  52. except ImportError:
  53. # The returned function won't get executed, just ignore the error
  54. pass
  55. @functools.wraps(func)
  56. def f(*args, **kwargs):
  57. try:
  58. s = socket.socket(socket.AF_INET)
  59. _ssl.sslwrap(s._sock, 0, None, None,
  60. ssl.CERT_NONE, ssl.PROTOCOL_SSLv2, None, None)
  61. except ssl.SSLError as e:
  62. if (ssl.OPENSSL_VERSION_INFO == (0, 9, 8, 15, 15) and
  63. platform.linux_distribution() == ('debian', 'squeeze/sid', '')
  64. and 'Invalid SSL protocol variant specified' in str(e)):
  65. raise unittest.SkipTest("Patched Ubuntu OpenSSL breaks behaviour")
  66. return func(*args, **kwargs)
  67. return f
  68. else:
  69. return func
  70. class BasicSocketTests(unittest.TestCase):
  71. def test_constants(self):
  72. #ssl.PROTOCOL_SSLv2
  73. ssl.PROTOCOL_SSLv23
  74. ssl.PROTOCOL_SSLv3
  75. ssl.PROTOCOL_TLSv1
  76. ssl.CERT_NONE
  77. ssl.CERT_OPTIONAL
  78. ssl.CERT_REQUIRED
  79. def test_random(self):
  80. v = ssl.RAND_status()
  81. if test_support.verbose:
  82. sys.stdout.write("\n RAND_status is %d (%s)\n"
  83. % (v, (v and "sufficient randomness") or
  84. "insufficient randomness"))
  85. self.assertRaises(TypeError, ssl.RAND_egd, 1)
  86. self.assertRaises(TypeError, ssl.RAND_egd, 'foo', 1)
  87. ssl.RAND_add("this is a random string", 75.0)
  88. def test_parse_cert(self):
  89. # note that this uses an 'unofficial' function in _ssl.c,
  90. # provided solely for this test, to exercise the certificate
  91. # parsing code
  92. p = ssl._ssl._test_decode_cert(CERTFILE, False)
  93. if test_support.verbose:
  94. sys.stdout.write("\n" + pprint.pformat(p) + "\n")
  95. self.assertEqual(p['subject'],
  96. ((('countryName', 'XY'),),
  97. (('localityName', 'Castle Anthrax'),),
  98. (('organizationName', 'Python Software Foundation'),),
  99. (('commonName', 'localhost'),))
  100. )
  101. self.assertEqual(p['subjectAltName'], (('DNS', 'localhost'),))
  102. # Issue #13034: the subjectAltName in some certificates
  103. # (notably projects.developer.nokia.com:443) wasn't parsed
  104. p = ssl._ssl._test_decode_cert(NOKIACERT)
  105. if test_support.verbose:
  106. sys.stdout.write("\n" + pprint.pformat(p) + "\n")
  107. self.assertEqual(p['subjectAltName'],
  108. (('DNS', 'projects.developer.nokia.com'),
  109. ('DNS', 'projects.forum.nokia.com'))
  110. )
  111. def test_DER_to_PEM(self):
  112. with open(SVN_PYTHON_ORG_ROOT_CERT, 'r') as f:
  113. pem = f.read()
  114. d1 = ssl.PEM_cert_to_DER_cert(pem)
  115. p2 = ssl.DER_cert_to_PEM_cert(d1)
  116. d2 = ssl.PEM_cert_to_DER_cert(p2)
  117. self.assertEqual(d1, d2)
  118. if not p2.startswith(ssl.PEM_HEADER + '\n'):
  119. self.fail("DER-to-PEM didn't include correct header:\n%r\n" % p2)
  120. if not p2.endswith('\n' + ssl.PEM_FOOTER + '\n'):
  121. self.fail("DER-to-PEM didn't include correct footer:\n%r\n" % p2)
  122. def test_openssl_version(self):
  123. n = ssl.OPENSSL_VERSION_NUMBER
  124. t = ssl.OPENSSL_VERSION_INFO
  125. s = ssl.OPENSSL_VERSION
  126. self.assertIsInstance(n, (int, long))
  127. self.assertIsInstance(t, tuple)
  128. self.assertIsInstance(s, str)
  129. # Some sanity checks follow
  130. # >= 0.9
  131. self.assertGreaterEqual(n, 0x900000)
  132. # < 2.0
  133. self.assertLess(n, 0x20000000)
  134. major, minor, fix, patch, status = t
  135. self.assertGreaterEqual(major, 0)
  136. self.assertLess(major, 2)
  137. self.assertGreaterEqual(minor, 0)
  138. self.assertLess(minor, 256)
  139. self.assertGreaterEqual(fix, 0)
  140. self.assertLess(fix, 256)
  141. self.assertGreaterEqual(patch, 0)
  142. self.assertLessEqual(patch, 26)
  143. self.assertGreaterEqual(status, 0)
  144. self.assertLessEqual(status, 15)
  145. # Version string as returned by OpenSSL, the format might change
  146. self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)),
  147. (s, t))
  148. def test_ciphers(self):
  149. if not test_support.is_resource_enabled('network'):
  150. return
  151. remote = ("svn.python.org", 443)
  152. with test_support.transient_internet(remote[0]):
  153. s = ssl.wrap_socket(socket.socket(socket.AF_INET),
  154. cert_reqs=ssl.CERT_NONE, ciphers="ALL")
  155. s.connect(remote)
  156. s = ssl.wrap_socket(socket.socket(socket.AF_INET),
  157. cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT")
  158. s.connect(remote)
  159. # Error checking occurs when connecting, because the SSL context
  160. # isn't created before.
  161. s = ssl.wrap_socket(socket.socket(socket.AF_INET),
  162. cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
  163. with self.assertRaisesRegexp(ssl.SSLError, "No cipher can be selected"):
  164. s.connect(remote)
  165. @test_support.cpython_only
  166. def test_refcycle(self):
  167. # Issue #7943: an SSL object doesn't create reference cycles with
  168. # itself.
  169. s = socket.socket(socket.AF_INET)
  170. ss = ssl.wrap_socket(s)
  171. wr = weakref.ref(ss)
  172. del ss
  173. self.assertEqual(wr(), None)
  174. def test_wrapped_unconnected(self):
  175. # The _delegate_methods in socket.py are correctly delegated to by an
  176. # unconnected SSLSocket, so they will raise a socket.error rather than
  177. # something unexpected like TypeError.
  178. s = socket.socket(socket.AF_INET)
  179. ss = ssl.wrap_socket(s)
  180. self.assertRaises(socket.error, ss.recv, 1)
  181. self.assertRaises(socket.error, ss.recv_into, bytearray(b'x'))
  182. self.assertRaises(socket.error, ss.recvfrom, 1)
  183. self.assertRaises(socket.error, ss.recvfrom_into, bytearray(b'x'), 1)
  184. self.assertRaises(socket.error, ss.send, b'x')
  185. self.assertRaises(socket.error, ss.sendto, b'x', ('0.0.0.0', 0))
  186. class NetworkedTests(unittest.TestCase):
  187. def test_connect(self):
  188. with test_support.transient_internet("svn.python.org"):
  189. s = ssl.wrap_socket(socket.socket(socket.AF_INET),
  190. cert_reqs=ssl.CERT_NONE)
  191. s.connect(("svn.python.org", 443))
  192. c = s.getpeercert()
  193. if c:
  194. self.fail("Peer cert %s shouldn't be here!")
  195. s.close()
  196. # this should fail because we have no verification certs
  197. s = ssl.wrap_socket(socket.socket(socket.AF_INET),
  198. cert_reqs=ssl.CERT_REQUIRED)
  199. try:
  200. s.connect(("svn.python.org", 443))
  201. except ssl.SSLError:
  202. pass
  203. finally:
  204. s.close()
  205. # this should succeed because we specify the root cert
  206. s = ssl.wrap_socket(socket.socket(socket.AF_INET),
  207. cert_reqs=ssl.CERT_REQUIRED,
  208. ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
  209. try:
  210. s.connect(("svn.python.org", 443))
  211. finally:
  212. s.close()
  213. def test_connect_ex(self):
  214. # Issue #11326: check connect_ex() implementation
  215. with test_support.transient_internet("svn.python.org"):
  216. s = ssl.wrap_socket(socket.socket(socket.AF_INET),
  217. cert_reqs=ssl.CERT_REQUIRED,
  218. ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
  219. try:
  220. self.assertEqual(0, s.connect_ex(("svn.python.org", 443)))
  221. self.assertTrue(s.getpeercert())
  222. finally:
  223. s.close()
  224. def test_non_blocking_connect_ex(self):
  225. # Issue #11326: non-blocking connect_ex() should allow handshake
  226. # to proceed after the socket gets ready.
  227. with test_support.transient_internet("svn.python.org"):
  228. s = ssl.wrap_socket(socket.socket(socket.AF_INET),
  229. cert_reqs=ssl.CERT_REQUIRED,
  230. ca_certs=SVN_PYTHON_ORG_ROOT_CERT,
  231. do_handshake_on_connect=False)
  232. try:
  233. s.setblocking(False)
  234. rc = s.connect_ex(('svn.python.org', 443))
  235. # EWOULDBLOCK under Windows, EINPROGRESS elsewhere
  236. self.assertIn(rc, (0, errno.EINPROGRESS, errno.EWOULDBLOCK))
  237. # Wait for connect to finish
  238. select.select([], [s], [], 5.0)
  239. # Non-blocking handshake
  240. while True:
  241. try:
  242. s.do_handshake()
  243. break
  244. except ssl.SSLError as err:
  245. if err.args[0] == ssl.SSL_ERROR_WANT_READ:
  246. select.select([s], [], [], 5.0)
  247. elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
  248. select.select([], [s], [], 5.0)
  249. else:
  250. raise
  251. # SSL established
  252. self.assertTrue(s.getpeercert())
  253. finally:
  254. s.close()
  255. def test_timeout_connect_ex(self):
  256. # Issue #12065: on a timeout, connect_ex() should return the original
  257. # errno (mimicking the behaviour of non-SSL sockets).
  258. with test_support.transient_internet("svn.python.org"):
  259. s = ssl.wrap_socket(socket.socket(socket.AF_INET),
  260. cert_reqs=ssl.CERT_REQUIRED,
  261. ca_certs=SVN_PYTHON_ORG_ROOT_CERT,
  262. do_handshake_on_connect=False)
  263. try:
  264. s.settimeout(0.0000001)
  265. rc = s.connect_ex(('svn.python.org', 443))
  266. if rc == 0:
  267. self.skipTest("svn.python.org responded too quickly")
  268. self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK))
  269. finally:
  270. s.close()
  271. def test_connect_ex_error(self):
  272. with test_support.transient_internet("svn.python.org"):
  273. s = ssl.wrap_socket(socket.socket(socket.AF_INET),
  274. cert_reqs=ssl.CERT_REQUIRED,
  275. ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
  276. try:
  277. self.assertEqual(errno.ECONNREFUSED,
  278. s.connect_ex(("svn.python.org", 444)))
  279. finally:
  280. s.close()
  281. @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
  282. def test_makefile_close(self):
  283. # Issue #5238: creating a file-like object with makefile() shouldn't
  284. # delay closing the underlying "real socket" (here tested with its
  285. # file descriptor, hence skipping the test under Windows).
  286. with test_support.transient_internet("svn.python.org"):
  287. ss = ssl.wrap_socket(socket.socket(socket.AF_INET))
  288. ss.connect(("svn.python.org", 443))
  289. fd = ss.fileno()
  290. f = ss.makefile()
  291. f.close()
  292. # The fd is still open
  293. os.read(fd, 0)
  294. # Closing the SSL socket should close the fd too
  295. ss.close()
  296. gc.collect()
  297. with self.assertRaises(OSError) as e:
  298. os.read(fd, 0)
  299. self.assertEqual(e.exception.errno, errno.EBADF)
  300. def test_non_blocking_handshake(self):
  301. with test_support.transient_internet("svn.python.org"):
  302. s = socket.socket(socket.AF_INET)
  303. s.connect(("svn.python.org", 443))
  304. s.setblocking(False)
  305. s = ssl.wrap_socket(s,
  306. cert_reqs=ssl.CERT_NONE,
  307. do_handshake_on_connect=False)
  308. count = 0
  309. while True:
  310. try:
  311. count += 1
  312. s.do_handshake()
  313. break
  314. except ssl.SSLError, err:
  315. if err.args[0] == ssl.SSL_ERROR_WANT_READ:
  316. select.select([s], [], [])
  317. elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
  318. select.select([], [s], [])
  319. else:
  320. raise
  321. s.close()
  322. if test_support.verbose:
  323. sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
  324. def test_get_server_certificate(self):
  325. with test_support.transient_internet("svn.python.org"):
  326. pem = ssl.get_server_certificate(("svn.python.org", 443))
  327. if not pem:
  328. self.fail("No server certificate on svn.python.org:443!")
  329. try:
  330. pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
  331. except ssl.SSLError:
  332. #should fail
  333. pass
  334. else:
  335. self.fail("Got server certificate %s for svn.python.org!" % pem)
  336. pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
  337. if not pem:
  338. self.fail("No server certificate on svn.python.org:443!")
  339. if test_support.verbose:
  340. sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
  341. def test_algorithms(self):
  342. # Issue #8484: all algorithms should be available when verifying a
  343. # certificate.
  344. # SHA256 was added in OpenSSL 0.9.8
  345. if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
  346. self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
  347. self.skipTest("remote host needs SNI, only available on Python 3.2+")
  348. # NOTE: https://sha2.hboeck.de is another possible test host
  349. remote = ("sha256.tbs-internet.com", 443)
  350. sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
  351. with test_support.transient_internet("sha256.tbs-internet.com"):
  352. s = ssl.wrap_socket(socket.socket(socket.AF_INET),
  353. cert_reqs=ssl.CERT_REQUIRED,
  354. ca_certs=sha256_cert,)
  355. try:
  356. s.connect(remote)
  357. if test_support.verbose:
  358. sys.stdout.write("\nCipher with %r is %r\n" %
  359. (remote, s.cipher()))
  360. sys.stdout.write("Certificate is:\n%s\n" %
  361. pprint.pformat(s.getpeercert()))
  362. finally:
  363. s.close()
  364. try:
  365. import threading
  366. except ImportError:
  367. _have_threads = False
  368. else:
  369. _have_threads = True
  370. class ThreadedEchoServer(threading.Thread):
  371. class ConnectionHandler(threading.Thread):
  372. """A mildly complicated class, because we want it to work both
  373. with and without the SSL wrapper around the socket connection, so
  374. that we can test the STARTTLS functionality."""
  375. def __init__(self, server, connsock):
  376. self.server = server
  377. self.running = False
  378. self.sock = connsock
  379. self.sock.setblocking(1)
  380. self.sslconn = None
  381. threading.Thread.__init__(self)
  382. self.daemon = True
  383. def show_conn_details(self):
  384. if self.server.certreqs == ssl.CERT_REQUIRED:
  385. cert = self.sslconn.getpeercert()
  386. if test_support.verbose and self.server.chatty:
  387. sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
  388. cert_binary = self.sslconn.getpeercert(True)
  389. if test_support.verbose and self.server.chatty:
  390. sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
  391. cipher = self.sslconn.cipher()
  392. if test_support.verbose and self.server.chatty:
  393. sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
  394. def wrap_conn(self):
  395. try:
  396. self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
  397. certfile=self.server.certificate,
  398. ssl_version=self.server.protocol,
  399. ca_certs=self.server.cacerts,
  400. cert_reqs=self.server.certreqs,
  401. ciphers=self.server.ciphers)
  402. except ssl.SSLError as e:
  403. # XXX Various errors can have happened here, for example
  404. # a mismatching protocol version, an invalid certificate,
  405. # or a low-level bug. This should be made more discriminating.
  406. self.server.conn_errors.append(e)
  407. if self.server.chatty:
  408. handle_error("\n server: bad connection attempt from " +
  409. str(self.sock.getpeername()) + ":\n")
  410. self.close()
  411. self.running = False
  412. self.server.stop()
  413. return False
  414. else:
  415. return True
  416. def read(self):
  417. if self.sslconn:
  418. return self.sslconn.read()
  419. else:
  420. return self.sock.recv(1024)
  421. def write(self, bytes):
  422. if self.sslconn:
  423. return self.sslconn.write(bytes)
  424. else:
  425. return self.sock.send(bytes)
  426. def close(self):
  427. if self.sslconn:
  428. self.sslconn.close()
  429. else:
  430. self.sock._sock.close()
  431. def run(self):
  432. self.running = True
  433. if not self.server.starttls_server:
  434. if isinstance(self.sock, ssl.SSLSocket):
  435. self.sslconn = self.sock
  436. elif not self.wrap_conn():
  437. return
  438. self.show_conn_details()
  439. while self.running:
  440. try:
  441. msg = self.read()
  442. if not msg:
  443. # eof, so quit this handler
  444. self.running = False
  445. self.close()
  446. elif msg.strip() == 'over':
  447. if test_support.verbose and self.server.connectionchatty:
  448. sys.stdout.write(" server: client closed connection\n")
  449. self.close()
  450. return
  451. elif self.server.starttls_server and msg.strip() == 'STARTTLS':
  452. if test_support.verbose and self.server.connectionchatty:
  453. sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
  454. self.write("OK\n")
  455. if not self.wrap_conn():
  456. return
  457. elif self.server.starttls_server and self.sslconn and msg.strip() == 'ENDTLS':
  458. if test_support.verbose and self.server.connectionchatty:
  459. sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
  460. self.write("OK\n")
  461. self.sslconn.unwrap()
  462. self.sslconn = None
  463. if test_support.verbose and self.server.connectionchatty:
  464. sys.stdout.write(" server: connection is now unencrypted...\n")
  465. else:
  466. if (test_support.verbose and
  467. self.server.connectionchatty):
  468. ctype = (self.sslconn and "encrypted") or "unencrypted"
  469. sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
  470. % (repr(msg), ctype, repr(msg.lower()), ctype))
  471. self.write(msg.lower())
  472. except ssl.SSLError:
  473. if self.server.chatty:
  474. handle_error("Test server failure:\n")
  475. self.close()
  476. self.running = False
  477. # normally, we'd just stop here, but for the test
  478. # harness, we want to stop the server
  479. self.server.stop()
  480. def __init__(self, certificate, ssl_version=None,
  481. certreqs=None, cacerts=None,
  482. chatty=True, connectionchatty=False, starttls_server=False,
  483. wrap_accepting_socket=False, ciphers=None):
  484. if ssl_version is None:
  485. ssl_version = ssl.PROTOCOL_TLSv1
  486. if certreqs is None:
  487. certreqs = ssl.CERT_NONE
  488. self.certificate = certificate
  489. self.protocol = ssl_version
  490. self.certreqs = certreqs
  491. self.cacerts = cacerts
  492. self.ciphers = ciphers
  493. self.chatty = chatty
  494. self.connectionchatty = connectionchatty
  495. self.starttls_server = starttls_server
  496. self.sock = socket.socket()
  497. self.flag = None
  498. if wrap_accepting_socket:
  499. self.sock = ssl.wrap_socket(self.sock, server_side=True,
  500. certfile=self.certificate,
  501. cert_reqs = self.certreqs,
  502. ca_certs = self.cacerts,
  503. ssl_version = self.protocol,
  504. ciphers = self.ciphers)
  505. if test_support.verbose and self.chatty:
  506. sys.stdout.write(' server: wrapped server socket as %s\n' % str(self.sock))
  507. self.port = test_support.bind_port(self.sock)
  508. self.active = False
  509. self.conn_errors = []
  510. threading.Thread.__init__(self)
  511. self.daemon = True
  512. def __enter__(self):
  513. self.start(threading.Event())
  514. self.flag.wait()
  515. return self
  516. def __exit__(self, *args):
  517. self.stop()
  518. self.join()
  519. def start(self, flag=None):
  520. self.flag = flag
  521. threading.Thread.start(self)
  522. def run(self):
  523. self.sock.settimeout(0.05)
  524. self.sock.listen(5)
  525. self.active = True
  526. if self.flag:
  527. # signal an event
  528. self.flag.set()
  529. while self.active:
  530. try:
  531. newconn, connaddr = self.sock.accept()
  532. if test_support.verbose and self.chatty:
  533. sys.stdout.write(' server: new connection from '
  534. + str(connaddr) + '\n')
  535. handler = self.ConnectionHandler(self, newconn)
  536. handler.start()
  537. handler.join()
  538. except socket.timeout:
  539. pass
  540. except KeyboardInterrupt:
  541. self.stop()
  542. self.sock.close()
  543. def stop(self):
  544. self.active = False
  545. class AsyncoreEchoServer(threading.Thread):
  546. class EchoServer(asyncore.dispatcher):
  547. class ConnectionHandler(asyncore.dispatcher_with_send):
  548. def __init__(self, conn, certfile):
  549. asyncore.dispatcher_with_send.__init__(self, conn)
  550. self.socket = ssl.wrap_socket(conn, server_side=True,
  551. certfile=certfile,
  552. do_handshake_on_connect=False)
  553. self._ssl_accepting = True
  554. def readable(self):
  555. if isinstance(self.socket, ssl.SSLSocket):
  556. while self.socket.pending() > 0:
  557. self.handle_read_event()
  558. return True
  559. def _do_ssl_handshake(self):
  560. try:
  561. self.socket.do_handshake()
  562. except ssl.SSLError, err:
  563. if err.args[0] in (ssl.SSL_ERROR_WANT_READ,
  564. ssl.SSL_ERROR_WANT_WRITE):
  565. return
  566. elif err.args[0] == ssl.SSL_ERROR_EOF:
  567. return self.handle_close()
  568. raise
  569. except socket.error, err:
  570. if err.args[0] == errno.ECONNABORTED:
  571. return self.handle_close()
  572. else:
  573. self._ssl_accepting = False
  574. def handle_read(self):
  575. if self._ssl_accepting:
  576. self._do_ssl_handshake()
  577. else:
  578. data = self.recv(1024)
  579. if data and data.strip() != 'over':
  580. self.send(data.lower())
  581. def handle_close(self):
  582. self.close()
  583. if test_support.verbose:
  584. sys.stdout.write(" server: closed connection %s\n" % self.socket)
  585. def handle_error(self):
  586. raise
  587. def __init__(self, certfile):
  588. self.certfile = certfile
  589. asyncore.dispatcher.__init__(self)
  590. self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
  591. self.port = test_support.bind_port(self.socket)
  592. self.listen(5)
  593. def handle_accept(self):
  594. sock_obj, addr = self.accept()
  595. if test_support.verbose:
  596. sys.stdout.write(" server: new connection from %s:%s\n" %addr)
  597. self.ConnectionHandler(sock_obj, self.certfile)
  598. def handle_error(self):
  599. raise
  600. def __init__(self, certfile):
  601. self.flag = None
  602. self.active = False
  603. self.server = self.EchoServer(certfile)
  604. self.port = self.server.port
  605. threading.Thread.__init__(self)
  606. self.daemon = True
  607. def __str__(self):
  608. return "<%s %s>" % (self.__class__.__name__, self.server)
  609. def __enter__(self):
  610. self.start(threading.Event())
  611. self.flag.wait()
  612. return self
  613. def __exit__(self, *args):
  614. if test_support.verbose:
  615. sys.stdout.write(" cleanup: stopping server.\n")
  616. self.stop()
  617. if test_support.verbose:
  618. sys.stdout.write(" cleanup: joining server thread.\n")
  619. self.join()
  620. if test_support.verbose:
  621. sys.stdout.write(" cleanup: successfully joined.\n")
  622. def start(self, flag=None):
  623. self.flag = flag
  624. threading.Thread.start(self)
  625. def run(self):
  626. self.active = True
  627. if self.flag:
  628. self.flag.set()
  629. while self.active:
  630. asyncore.loop(0.05)
  631. def stop(self):
  632. self.active = False
  633. self.server.close()
  634. class SocketServerHTTPSServer(threading.Thread):
  635. class HTTPSServer(HTTPServer):
  636. def __init__(self, server_address, RequestHandlerClass, certfile):
  637. HTTPServer.__init__(self, server_address, RequestHandlerClass)
  638. # we assume the certfile contains both private key and certificate
  639. self.certfile = certfile
  640. self.allow_reuse_address = True
  641. def __str__(self):
  642. return ('<%s %s:%s>' %
  643. (self.__class__.__name__,
  644. self.server_name,
  645. self.server_port))
  646. def get_request(self):
  647. # override this to wrap socket with SSL
  648. sock, addr = self.socket.accept()
  649. sslconn = ssl.wrap_socket(sock, server_side=True,
  650. certfile=self.certfile)
  651. return sslconn, addr
  652. class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
  653. # need to override translate_path to get a known root,
  654. # instead of using os.curdir, since the test could be
  655. # run from anywhere
  656. server_version = "TestHTTPS/1.0"
  657. root = None
  658. def translate_path(self, path):
  659. """Translate a /-separated PATH to the local filename syntax.
  660. Components that mean special things to the local file system
  661. (e.g. drive or directory names) are ignored. (XXX They should
  662. probably be diagnosed.)
  663. """
  664. # abandon query parameters
  665. path = urlparse.urlparse(path)[2]
  666. path = os.path.normpath(urllib.unquote(path))
  667. words = path.split('/')
  668. words = filter(None, words)
  669. path = self.root
  670. for word in words:
  671. drive, word = os.path.splitdrive(word)
  672. head, word = os.path.split(word)
  673. if word in self.root: continue
  674. path = os.path.join(path, word)
  675. return path
  676. def log_message(self, format, *args):
  677. # we override this to suppress logging unless "verbose"
  678. if test_support.verbose:
  679. sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
  680. (self.server.server_address,
  681. self.server.server_port,
  682. self.request.cipher(),
  683. self.log_date_time_string(),
  684. format%args))
  685. def __init__(self, certfile):
  686. self.flag = None
  687. self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
  688. self.server = self.HTTPSServer(
  689. (HOST, 0), self.RootedHTTPRequestHandler, certfile)
  690. self.port = self.server.server_port
  691. threading.Thread.__init__(self)
  692. self.daemon = True
  693. def __str__(self):
  694. return "<%s %s>" % (self.__class__.__name__, self.server)
  695. def start(self, flag=None):
  696. self.flag = flag
  697. threading.Thread.start(self)
  698. def run(self):
  699. if self.flag:
  700. self.flag.set()
  701. self.server.serve_forever(0.05)
  702. def stop(self):
  703. self.server.shutdown()
  704. def bad_cert_test(certfile):
  705. """
  706. Launch a server with CERT_REQUIRED, and check that trying to
  707. connect to it with the given client certificate fails.
  708. """
  709. server = ThreadedEchoServer(CERTFILE,
  710. certreqs=ssl.CERT_REQUIRED,
  711. cacerts=CERTFILE, chatty=False)
  712. with server:
  713. try:
  714. s = ssl.wrap_socket(socket.socket(),
  715. certfile=certfile,
  716. ssl_version=ssl.PROTOCOL_TLSv1)
  717. s.connect((HOST, server.port))
  718. except ssl.SSLError, x:
  719. if test_support.verbose:
  720. sys.stdout.write("\nSSLError is %s\n" % x[1])
  721. except socket.error, x:
  722. if test_support.verbose:
  723. sys.stdout.write("\nsocket.error is %s\n" % x[1])
  724. else:
  725. raise AssertionError("Use of invalid cert should have failed!")
  726. def server_params_test(certfile, protocol, certreqs, cacertsfile,
  727. client_certfile, client_protocol=None, indata="FOO\n",
  728. ciphers=None, chatty=True, connectionchatty=False,
  729. wrap_accepting_socket=False):
  730. """
  731. Launch a server, connect a client to it and try various reads
  732. and writes.
  733. """
  734. server = ThreadedEchoServer(certfile,
  735. certreqs=certreqs,
  736. ssl_version=protocol,
  737. cacerts=cacertsfile,
  738. ciphers=ciphers,
  739. chatty=chatty,
  740. connectionchatty=connectionchatty,
  741. wrap_accepting_socket=wrap_accepting_socket)
  742. with server:
  743. # try to connect
  744. if client_protocol is None:
  745. client_protocol = protocol
  746. s = ssl.wrap_socket(socket.socket(),
  747. certfile=client_certfile,
  748. ca_certs=cacertsfile,
  749. ciphers=ciphers,
  750. cert_reqs=certreqs,
  751. ssl_version=client_protocol)
  752. s.connect((HOST, server.port))
  753. for arg in [indata, bytearray(indata), memoryview(indata)]:
  754. if connectionchatty:
  755. if test_support.verbose:
  756. sys.stdout.write(
  757. " client: sending %s...\n" % (repr(arg)))
  758. s.write(arg)
  759. outdata = s.read()
  760. if connectionchatty:
  761. if test_support.verbose:
  762. sys.stdout.write(" client: read %s\n" % repr(outdata))
  763. if outdata != indata.lower():
  764. raise AssertionError(
  765. "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
  766. % (outdata[:min(len(outdata),20)], len(outdata),
  767. indata[:min(len(indata),20)].lower(), len(indata)))
  768. s.write("over\n")
  769. if connectionchatty:
  770. if test_support.verbose:
  771. sys.stdout.write(" client: closing connection.\n")
  772. s.close()
  773. def try_protocol_combo(server_protocol,
  774. client_protocol,
  775. expect_success,
  776. certsreqs=None):
  777. if certsreqs is None:
  778. certsreqs = ssl.CERT_NONE
  779. certtype = {
  780. ssl.CERT_NONE: "CERT_NONE",
  781. ssl.CERT_OPTIONAL: "CERT_OPTIONAL",
  782. ssl.CERT_REQUIRED: "CERT_REQUIRED",
  783. }[certsreqs]
  784. if test_support.verbose:
  785. formatstr = (expect_success and " %s->%s %s\n") or " {%s->%s} %s\n"
  786. sys.stdout.write(formatstr %
  787. (ssl.get_protocol_name(client_protocol),
  788. ssl.get_protocol_name(server_protocol),
  789. certtype))
  790. try:
  791. # NOTE: we must enable "ALL" ciphers, otherwise an SSLv23 client
  792. # will send an SSLv3 hello (rather than SSLv2) starting from
  793. # OpenSSL 1.0.0 (see issue #8322).
  794. server_params_test(CERTFILE, server_protocol, certsreqs,
  795. CERTFILE, CERTFILE, client_protocol,
  796. ciphers="ALL", chatty=False)
  797. # Protocol mismatch can result in either an SSLError, or a
  798. # "Connection reset by peer" error.
  799. except ssl.SSLError:
  800. if expect_success:
  801. raise
  802. except socket.error as e:
  803. if expect_success or e.errno != errno.ECONNRESET:
  804. raise
  805. else:
  806. if not expect_success:
  807. raise AssertionError(
  808. "Client protocol %s succeeded with server protocol %s!"
  809. % (ssl.get_protocol_name(client_protocol),
  810. ssl.get_protocol_name(server_protocol)))
  811. class ThreadedTests(unittest.TestCase):
  812. def test_rude_shutdown(self):
  813. """A brutal shutdown of an SSL server should raise an IOError
  814. in the client when attempting handshake.
  815. """
  816. listener_ready = threading.Event()
  817. listener_gone = threading.Event()
  818. s = socket.socket()
  819. port = test_support.bind_port(s, HOST)
  820. # `listener` runs in a thread. It sits in an accept() until
  821. # the main thread connects. Then it rudely closes the socket,
  822. # and sets Event `listener_gone` to let the main thread know
  823. # the socket is gone.
  824. def listener():
  825. s.listen(5)
  826. listener_ready.set()
  827. s.accept()
  828. s.close()
  829. listener_gone.set()
  830. def connector():
  831. listener_ready.wait()
  832. c = socket.socket()
  833. c.connect((HOST, port))
  834. listener_gone.wait()
  835. try:
  836. ssl_sock = ssl.wrap_socket(c)
  837. except IOError:
  838. pass
  839. else:
  840. self.fail('connecting to closed SSL socket should have failed')
  841. t = threading.Thread(target=listener)
  842. t.start()
  843. try:
  844. connector()
  845. finally:
  846. t.join()
  847. @skip_if_broken_ubuntu_ssl
  848. def test_echo(self):
  849. """Basic test of an SSL client connecting to a server"""
  850. if test_support.verbose:
  851. sys.stdout.write("\n")
  852. server_params_test(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
  853. CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
  854. chatty=True, connectionchatty=True)
  855. def test_getpeercert(self):
  856. if test_support.verbose:
  857. sys.stdout.write("\n")
  858. s2 = socket.socket()
  859. server = ThreadedEchoServer(CERTFILE,
  860. certreqs=ssl.CERT_NONE,
  861. ssl_version=ssl.PROTOCOL_SSLv23,
  862. cacerts=CERTFILE,
  863. chatty=False)
  864. with server:
  865. s = ssl.wrap_socket(socket.socket(),
  866. certfile=CERTFILE,
  867. ca_certs=CERTFILE,
  868. cert_reqs=ssl.CERT_REQUIRED,
  869. ssl_version=ssl.PROTOCOL_SSLv23)
  870. s.connect((HOST, server.port))
  871. cert = s.getpeercert()
  872. self.assertTrue(cert, "Can't get peer certificate.")
  873. cipher = s.cipher()
  874. if test_support.verbose:
  875. sys.stdout.write(pprint.pformat(cert) + '\n')
  876. sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
  877. if 'subject' not in cert:
  878. self.fail("No subject field in certificate: %s." %
  879. pprint.pformat(cert))
  880. if ((('organizationName', 'Python Software Foundation'),)
  881. not in cert['subject']):
  882. self.fail(
  883. "Missing or invalid 'organizationName' field in certificate subject; "
  884. "should be 'Python Software Foundation'.")
  885. s.close()
  886. def test_empty_cert(self):
  887. """Connecting with an empty cert file"""
  888. bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
  889. "nullcert.pem"))
  890. def test_malformed_cert(self):
  891. """Connecting with a badly formatted certificate (syntax error)"""
  892. bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
  893. "badcert.pem"))
  894. def test_nonexisting_cert(self):
  895. """Connecting with a non-existing cert file"""
  896. bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
  897. "wrongcert.pem"))
  898. def test_malformed_key(self):
  899. """Connecting with a badly formatted key (syntax error)"""
  900. bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
  901. "badkey.pem"))
  902. @skip_if_broken_ubuntu_ssl
  903. def test_protocol_sslv2(self):
  904. """Connecting to an SSLv2 server with various client options"""
  905. if test_support.verbose:
  906. sys.stdout.write("\n")
  907. if not hasattr(ssl, 'PROTOCOL_SSLv2'):
  908. self.skipTest("PROTOCOL_SSLv2 needed")
  909. try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
  910. try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
  911. try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
  912. try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
  913. try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
  914. try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
  915. @skip_if_broken_ubuntu_ssl
  916. def test_protocol_sslv23(self):
  917. """Connecting to an SSLv23 server with various client options"""
  918. if test_support.verbose:
  919. sys.stdout.write("\n")
  920. try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
  921. try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
  922. try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
  923. try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
  924. try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
  925. try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
  926. try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
  927. try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
  928. try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
  929. @skip_if_broken_ubuntu_ssl
  930. def test_protocol_sslv3(self):
  931. """Connecting to an SSLv3 server with various client options"""
  932. if test_support.verbose:
  933. sys.stdout.write("\n")
  934. try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
  935. try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
  936. try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
  937. if hasattr(ssl, 'PROTOCOL_SSLv2'):
  938. try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
  939. try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
  940. @skip_if_broken_ubuntu_ssl
  941. def test_protocol_tlsv1(self):
  942. """Connecting to a TLSv1 server with various client options"""
  943. if test_support.verbose:
  944. sys.stdout.write("\n")
  945. try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
  946. try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
  947. try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
  948. if hasattr(ssl, 'PROTOCOL_SSLv2'):
  949. try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
  950. try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
  951. def test_starttls(self):
  952. """Switching from clear text to encrypted and back again."""
  953. msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
  954. server = ThreadedEchoServer(CERTFILE,
  955. ssl_version=ssl.PROTOCOL_TLSv1,
  956. starttls_server=True,
  957. chatty=True,
  958. connectionchatty=True)
  959. wrapped = False
  960. with server:
  961. s = socket.socket()
  962. s.setblocking(1)
  963. s.connect((HOST, server.port))
  964. if test_support.verbose:
  965. sys.stdout.write("\n")
  966. for indata in msgs:
  967. if test_support.verbose:
  968. sys.stdout.write(
  969. " client: sending %s...\n" % repr(indata))
  970. if wrapped:
  971. conn.write(indata)
  972. outdata = conn.read()
  973. else:
  974. s.send(indata)
  975. outdata = s.recv(1024)
  976. if (indata == "STARTTLS" and
  977. outdata.strip().lower().startswith("ok")):
  978. # STARTTLS ok, switch to secure mode
  979. if test_support.verbose:
  980. sys.stdout.write(
  981. " client: read %s from server, starting TLS...\n"
  982. % repr(outdata))
  983. conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
  984. wrapped = True
  985. elif (indata == "ENDTLS" and
  986. outdata.strip().lower().startswith("ok")):
  987. # ENDTLS ok, switch back to clear text
  988. if test_support.verbose:
  989. sys.stdout.write(
  990. " client: read %s from server, ending TLS...\n"
  991. % repr(outdata))
  992. s = conn.unwrap()
  993. wrapped = False
  994. else:
  995. if test_support.verbose:
  996. sys.stdout.write(
  997. " client: read %s from server\n" % repr(outdata))
  998. if test_support.verbose:
  999. sys.stdout.write(" client: closing connection.\n")
  1000. if wrapped:
  1001. conn.write("over\n")
  1002. else:
  1003. s.send("over\n")
  1004. s.close()
  1005. def test_socketserver(self):
  1006. """Using a SocketServer to create and manage SSL connections."""
  1007. server = SocketServerHTTPSServer(CERTFILE)
  1008. flag = threading.Event()
  1009. server.start(flag)
  1010. # wait for it to start
  1011. flag.wait()
  1012. # try to connect
  1013. try:
  1014. if test_support.verbose:
  1015. sys.stdout.write('\n')
  1016. with open(CERTFILE, 'rb') as f:
  1017. d1 = f.read()
  1018. d2 = ''
  1019. # now fetch the same data from the HTTPS server
  1020. url = 'https://127.0.0.1:%d/%s' % (
  1021. server.port, os.path.split(CERTFILE)[1])
  1022. with test_support.check_py3k_warnings():
  1023. f = urllib.urlopen(url)
  1024. dlen = f.info().getheader("content-length")
  1025. if dlen and (int(dlen) > 0):
  1026. d2 = f.read(int(dlen))
  1027. if test_support.verbose:
  1028. sys.stdout.write(
  1029. " client: read %d bytes from remote server '%s'\n"
  1030. % (len(d2), server))
  1031. f.close()
  1032. self.assertEqual(d1, d2)
  1033. finally:
  1034. server.stop()
  1035. server.join()
  1036. def test_wrapped_accept(s

Large files files are truncated, but you can click here to view the full file