blob: 697971e0a57d97c764d50e6cf62ad6176908d553 [file] [log] [blame]
Thomas Woutersed03b412007-08-28 21:37:11 +00001# Test the support for SSL and sockets
2
3import sys
4import unittest
Christian Heimesc7f70692019-05-31 11:44:05 +02005import unittest.mock
Benjamin Petersonee8712c2008-05-20 21:35:26 +00006from test import support
Hai Shia7f5d932020-08-04 00:41:24 +08007from test.support import import_helper
8from test.support import os_helper
Serhiy Storchaka16994912020-04-25 10:06:29 +03009from test.support import socket_helper
Hai Shie80697d2020-05-28 06:10:27 +080010from test.support import threading_helper
Hai Shia7f5d932020-08-04 00:41:24 +080011from test.support import warnings_helper
Thomas Woutersed03b412007-08-28 21:37:11 +000012import socket
Bill Janssen6e027db2007-11-15 22:23:56 +000013import select
Thomas Woutersed03b412007-08-28 21:37:11 +000014import time
Antoine Pitroucfcd8ad2010-04-23 23:31:47 +000015import gc
Thomas Woutersed03b412007-08-28 21:37:11 +000016import os
Antoine Pitroucfcd8ad2010-04-23 23:31:47 +000017import errno
Thomas Woutersed03b412007-08-28 21:37:11 +000018import pprint
Antoine Pitrou803e6d62010-10-13 10:36:15 +000019import urllib.request
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020020import threading
Thomas Woutersed03b412007-08-28 21:37:11 +000021import traceback
Bill Janssen54cc54c2007-12-14 22:08:56 +000022import asyncore
Antoine Pitrou9d543662010-04-23 23:10:32 +000023import weakref
Antoine Pitrou15cee622010-08-04 16:45:21 +000024import platform
Christian Heimes892d66e2018-01-29 14:10:18 +010025import sysconfig
Christian Heimesdf6ac7e2019-09-26 17:02:59 +020026import functools
Christian Heimes888bbdc2017-09-07 14:18:21 -070027try:
28 import ctypes
29except ImportError:
30 ctypes = None
Thomas Woutersed03b412007-08-28 21:37:11 +000031
Hai Shia7f5d932020-08-04 00:41:24 +080032ssl = import_helper.import_module("ssl")
Antoine Pitrou05d936d2010-10-13 11:38:36 +000033
Ethan Furman503cdc72021-04-19 19:12:24 -070034from ssl import TLSVersion, _TLSContentType, _TLSMessageType
Martin Panter3840b2a2016-03-27 01:53:46 +000035
Paul Monsonf3550692019-06-19 13:09:54 -070036Py_DEBUG = hasattr(sys, 'gettotalrefcount')
37Py_DEBUG_WIN32 = Py_DEBUG and sys.platform == 'win32'
38
Antoine Pitrou2463e5f2013-03-28 22:24:43 +010039PROTOCOLS = sorted(ssl._PROTOCOL_NAMES)
Serhiy Storchaka16994912020-04-25 10:06:29 +030040HOST = socket_helper.HOST
Christian Heimesd37b74f2021-04-19 08:31:29 +020041IS_OPENSSL_3_0_0 = ssl.OPENSSL_VERSION_INFO >= (3, 0, 0)
Christian Heimes892d66e2018-01-29 14:10:18 +010042PY_SSL_DEFAULT_CIPHERS = sysconfig.get_config_var('PY_SSL_DEFAULT_CIPHERS')
Antoine Pitrou152efa22010-05-16 18:19:27 +000043
Victor Stinner3ef63442019-02-19 18:06:03 +010044PROTOCOL_TO_TLS_VERSION = {}
45for proto, ver in (
46 ("PROTOCOL_SSLv23", "SSLv3"),
47 ("PROTOCOL_TLSv1", "TLSv1"),
48 ("PROTOCOL_TLSv1_1", "TLSv1_1"),
49):
50 try:
51 proto = getattr(ssl, proto)
52 ver = getattr(ssl.TLSVersion, ver)
53 except AttributeError:
54 continue
55 PROTOCOL_TO_TLS_VERSION[proto] = ver
56
Christian Heimesefff7062013-11-21 03:35:02 +010057def data_file(*name):
58 return os.path.join(os.path.dirname(__file__), *name)
Antoine Pitrou152efa22010-05-16 18:19:27 +000059
Antoine Pitrou81564092010-10-08 23:06:24 +000060# The custom key and certificate files used in test_ssl are generated
61# using Lib/test/make_ssl_certs.py.
62# Other certificates are simply fetched from the Internet servers they
63# are meant to authenticate.
64
Antoine Pitrou152efa22010-05-16 18:19:27 +000065CERTFILE = data_file("keycert.pem")
Victor Stinner313a1202010-06-11 23:56:51 +000066BYTES_CERTFILE = os.fsencode(CERTFILE)
Antoine Pitrou152efa22010-05-16 18:19:27 +000067ONLYCERT = data_file("ssl_cert.pem")
68ONLYKEY = data_file("ssl_key.pem")
Victor Stinner313a1202010-06-11 23:56:51 +000069BYTES_ONLYCERT = os.fsencode(ONLYCERT)
70BYTES_ONLYKEY = os.fsencode(ONLYKEY)
Antoine Pitrou4fd1e6a2011-08-25 14:39:44 +020071CERTFILE_PROTECTED = data_file("keycert.passwd.pem")
72ONLYKEY_PROTECTED = data_file("ssl_key.passwd.pem")
73KEY_PASSWORD = "somepass"
Antoine Pitrou152efa22010-05-16 18:19:27 +000074CAPATH = data_file("capath")
Victor Stinner313a1202010-06-11 23:56:51 +000075BYTES_CAPATH = os.fsencode(CAPATH)
Christian Heimesefff7062013-11-21 03:35:02 +010076CAFILE_NEURONIO = data_file("capath", "4e1295a3.0")
77CAFILE_CACERT = data_file("capath", "5ed36f99.0")
78
Christian Heimesbd5c7d22018-01-20 15:16:30 +010079CERTFILE_INFO = {
80 'issuer': ((('countryName', 'XY'),),
81 (('localityName', 'Castle Anthrax'),),
82 (('organizationName', 'Python Software Foundation'),),
83 (('commonName', 'localhost'),)),
Christian Heimese6dac002018-08-30 07:25:49 +020084 'notAfter': 'Aug 26 14:23:15 2028 GMT',
85 'notBefore': 'Aug 29 14:23:15 2018 GMT',
86 'serialNumber': '98A7CF88C74A32ED',
Christian Heimesbd5c7d22018-01-20 15:16:30 +010087 'subject': ((('countryName', 'XY'),),
88 (('localityName', 'Castle Anthrax'),),
89 (('organizationName', 'Python Software Foundation'),),
90 (('commonName', 'localhost'),)),
91 'subjectAltName': (('DNS', 'localhost'),),
92 'version': 3
93}
Antoine Pitrou152efa22010-05-16 18:19:27 +000094
Christian Heimes22587792013-11-21 23:56:13 +010095# empty CRL
96CRLFILE = data_file("revocation.crl")
97
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +010098# Two keys and certs signed by the same CA (for SNI tests)
99SIGNED_CERTFILE = data_file("keycert3.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +0200100SIGNED_CERTFILE_HOSTNAME = 'localhost'
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100101
102SIGNED_CERTFILE_INFO = {
103 'OCSP': ('http://testca.pythontest.net/testca/ocsp/',),
104 'caIssuers': ('http://testca.pythontest.net/testca/pycacert.cer',),
105 'crlDistributionPoints': ('http://testca.pythontest.net/testca/revocation.crl',),
106 'issuer': ((('countryName', 'XY'),),
107 (('organizationName', 'Python Software Foundation CA'),),
108 (('commonName', 'our-ca-server'),)),
Christian Heimesb467d9a2021-04-17 10:07:19 +0200109 'notAfter': 'Oct 28 14:23:16 2037 GMT',
Christian Heimese6dac002018-08-30 07:25:49 +0200110 'notBefore': 'Aug 29 14:23:16 2018 GMT',
111 'serialNumber': 'CB2D80995A69525C',
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100112 'subject': ((('countryName', 'XY'),),
113 (('localityName', 'Castle Anthrax'),),
114 (('organizationName', 'Python Software Foundation'),),
115 (('commonName', 'localhost'),)),
116 'subjectAltName': (('DNS', 'localhost'),),
117 'version': 3
118}
119
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100120SIGNED_CERTFILE2 = data_file("keycert4.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +0200121SIGNED_CERTFILE2_HOSTNAME = 'fakehostname'
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100122SIGNED_CERTFILE_ECC = data_file("keycertecc.pem")
123SIGNED_CERTFILE_ECC_HOSTNAME = 'localhost-ecc'
124
Martin Panter3840b2a2016-03-27 01:53:46 +0000125# Same certificate as pycacert.pem, but without extra text in file
126SIGNING_CA = data_file("capath", "ceff1710.0")
Christian Heimes1c03abd2016-09-06 23:25:35 +0200127# cert with all kinds of subject alt names
128ALLSANFILE = data_file("allsans.pem")
Christian Heimes66e57422018-01-29 14:25:13 +0100129IDNSANSFILE = data_file("idnsans.pem")
Christian Heimesb467d9a2021-04-17 10:07:19 +0200130NOSANFILE = data_file("nosan.pem")
131NOSAN_HOSTNAME = 'localhost'
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100132
Martin Panter3d81d932016-01-14 09:36:00 +0000133REMOTE_HOST = "self-signed.pythontest.net"
Antoine Pitrou152efa22010-05-16 18:19:27 +0000134
135EMPTYCERT = data_file("nullcert.pem")
136BADCERT = data_file("badcert.pem")
Martin Panter407b62f2016-01-30 03:41:43 +0000137NONEXISTINGCERT = data_file("XXXnonexisting.pem")
Antoine Pitrou152efa22010-05-16 18:19:27 +0000138BADKEY = data_file("badkey.pem")
Antoine Pitroud8c347a2011-10-01 19:20:25 +0200139NOKIACERT = data_file("nokia.pem")
Christian Heimes824f7f32013-08-17 00:54:47 +0200140NULLBYTECERT = data_file("nullbytecert.pem")
Christian Heimesa37f5242019-01-15 23:47:42 +0100141TALOS_INVALID_CRLDP = data_file("talos-2019-0758.pem")
Antoine Pitrou152efa22010-05-16 18:19:27 +0000142
Christian Heimes88bfd0b2018-08-14 12:54:19 +0200143DHFILE = data_file("ffdh3072.pem")
Antoine Pitrou0e576f12011-12-22 10:03:38 +0100144BYTES_DHFILE = os.fsencode(DHFILE)
Thomas Woutersed03b412007-08-28 21:37:11 +0000145
Christian Heimes358cfd42016-09-10 22:43:48 +0200146# Not defined in all versions of OpenSSL
147OP_NO_COMPRESSION = getattr(ssl, "OP_NO_COMPRESSION", 0)
148OP_SINGLE_DH_USE = getattr(ssl, "OP_SINGLE_DH_USE", 0)
149OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0)
150OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0)
Christian Heimes05d9fe32018-02-27 08:55:39 +0100151OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0)
Christian Heimes6f37ebc2021-04-09 17:59:21 +0200152OP_IGNORE_UNEXPECTED_EOF = getattr(ssl, "OP_IGNORE_UNEXPECTED_EOF", 0)
Christian Heimes358cfd42016-09-10 22:43:48 +0200153
Christian Heimesf6c6b582021-03-18 23:06:50 +0100154# Ubuntu has patched OpenSSL and changed behavior of security level 2
155# see https://bugs.python.org/issue41561#msg389003
156def is_ubuntu():
157 try:
158 # Assume that any references of "ubuntu" implies Ubuntu-like distro
159 # The workaround is not required for 18.04, but doesn't hurt either.
160 with open("/etc/os-release", encoding="utf-8") as f:
161 return "ubuntu" in f.read()
162 except FileNotFoundError:
163 return False
164
165if is_ubuntu():
166 def seclevel_workaround(*ctxs):
167 """"Lower security level to '1' and allow all ciphers for TLS 1.0/1"""
168 for ctx in ctxs:
Christian Heimes34477502021-04-12 12:00:38 +0200169 if (
170 hasattr(ctx, "minimum_version") and
171 ctx.minimum_version <= ssl.TLSVersion.TLSv1_1
172 ):
Christian Heimesf6c6b582021-03-18 23:06:50 +0100173 ctx.set_ciphers("@SECLEVEL=1:ALL")
174else:
175 def seclevel_workaround(*ctxs):
176 pass
177
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100178
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200179def has_tls_protocol(protocol):
180 """Check if a TLS protocol is available and enabled
181
182 :param protocol: enum ssl._SSLMethod member or name
183 :return: bool
184 """
185 if isinstance(protocol, str):
186 assert protocol.startswith('PROTOCOL_')
187 protocol = getattr(ssl, protocol, None)
188 if protocol is None:
189 return False
190 if protocol in {
191 ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS_SERVER,
192 ssl.PROTOCOL_TLS_CLIENT
193 }:
194 # auto-negotiate protocols are always available
195 return True
196 name = protocol.name
197 return has_tls_version(name[len('PROTOCOL_'):])
198
199
200@functools.lru_cache
201def has_tls_version(version):
202 """Check if a TLS/SSL version is enabled
203
204 :param version: TLS version name or ssl.TLSVersion member
205 :return: bool
206 """
207 if version == "SSLv2":
208 # never supported and not even in TLSVersion enum
209 return False
210
211 if isinstance(version, str):
212 version = ssl.TLSVersion.__members__[version]
213
214 # check compile time flags like ssl.HAS_TLSv1_2
215 if not getattr(ssl, f'HAS_{version.name}'):
216 return False
217
Christian Heimes5151d642021-04-09 15:43:06 +0200218 if IS_OPENSSL_3_0_0 and version < ssl.TLSVersion.TLSv1_2:
219 # bpo43791: 3.0.0-alpha14 fails with TLSV1_ALERT_INTERNAL_ERROR
220 return False
221
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200222 # check runtime and dynamic crypto policy settings. A TLS version may
223 # be compiled in but disabled by a policy or config option.
Christian Heimes2875c602021-04-19 07:27:10 +0200224 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200225 if (
Christian Heimes9f772682019-09-26 18:23:17 +0200226 hasattr(ctx, 'minimum_version') and
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200227 ctx.minimum_version != ssl.TLSVersion.MINIMUM_SUPPORTED and
228 version < ctx.minimum_version
229 ):
230 return False
231 if (
Christian Heimes9f772682019-09-26 18:23:17 +0200232 hasattr(ctx, 'maximum_version') and
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200233 ctx.maximum_version != ssl.TLSVersion.MAXIMUM_SUPPORTED and
234 version > ctx.maximum_version
235 ):
236 return False
237
238 return True
239
240
241def requires_tls_version(version):
242 """Decorator to skip tests when a required TLS version is not available
243
244 :param version: TLS version name or ssl.TLSVersion member
245 :return:
246 """
247 def decorator(func):
248 @functools.wraps(func)
249 def wrapper(*args, **kw):
250 if not has_tls_version(version):
251 raise unittest.SkipTest(f"{version} is not available.")
252 else:
253 return func(*args, **kw)
254 return wrapper
255 return decorator
256
257
Thomas Woutersed03b412007-08-28 21:37:11 +0000258def handle_error(prefix):
259 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000260 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000261 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +0000262
Christian Heimesb7b92252018-02-25 09:49:31 +0100263
Antoine Pitrouc695c952014-04-28 20:57:36 +0200264def utc_offset(): #NOTE: ignore issues like #1647654
265 # local time = utc time + utc offset
266 if time.daylight and time.localtime().tm_isdst > 0:
267 return -time.altzone # seconds
268 return -time.timezone
269
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100270
Christian Heimes2875c602021-04-19 07:27:10 +0200271ignore_deprecation = warnings_helper.ignore_warnings(
272 category=DeprecationWarning
273)
Antoine Pitrou23df4832010-08-04 17:14:06 +0000274
Christian Heimes2875c602021-04-19 07:27:10 +0200275
276def test_wrap_socket(sock, *,
Christian Heimesd0486372016-09-10 23:23:33 +0200277 cert_reqs=ssl.CERT_NONE, ca_certs=None,
278 ciphers=None, certfile=None, keyfile=None,
279 **kwargs):
Christian Heimes2875c602021-04-19 07:27:10 +0200280 if not kwargs.get("server_side"):
281 kwargs["server_hostname"] = SIGNED_CERTFILE_HOSTNAME
282 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
283 else:
284 context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimesd0486372016-09-10 23:23:33 +0200285 if cert_reqs is not None:
Christian Heimesa170fa12017-09-15 20:27:30 +0200286 if cert_reqs == ssl.CERT_NONE:
287 context.check_hostname = False
Christian Heimesd0486372016-09-10 23:23:33 +0200288 context.verify_mode = cert_reqs
289 if ca_certs is not None:
290 context.load_verify_locations(ca_certs)
291 if certfile is not None or keyfile is not None:
292 context.load_cert_chain(certfile, keyfile)
293 if ciphers is not None:
294 context.set_ciphers(ciphers)
295 return context.wrap_socket(sock, **kwargs)
296
Christian Heimesa170fa12017-09-15 20:27:30 +0200297
298def testing_context(server_cert=SIGNED_CERTFILE):
299 """Create context
300
301 client_context, server_context, hostname = testing_context()
302 """
303 if server_cert == SIGNED_CERTFILE:
304 hostname = SIGNED_CERTFILE_HOSTNAME
305 elif server_cert == SIGNED_CERTFILE2:
306 hostname = SIGNED_CERTFILE2_HOSTNAME
Christian Heimesb467d9a2021-04-17 10:07:19 +0200307 elif server_cert == NOSANFILE:
308 hostname = NOSAN_HOSTNAME
Christian Heimesa170fa12017-09-15 20:27:30 +0200309 else:
310 raise ValueError(server_cert)
311
312 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
313 client_context.load_verify_locations(SIGNING_CA)
314
315 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
316 server_context.load_cert_chain(server_cert)
Christian Heimes9fb051f2018-09-23 08:32:31 +0200317 server_context.load_verify_locations(SIGNING_CA)
Christian Heimesa170fa12017-09-15 20:27:30 +0200318
319 return client_context, server_context, hostname
320
321
Antoine Pitrou152efa22010-05-16 18:19:27 +0000322class BasicSocketTests(unittest.TestCase):
Thomas Woutersed03b412007-08-28 21:37:11 +0000323
Antoine Pitrou480a1242010-04-28 21:37:09 +0000324 def test_constants(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000325 ssl.CERT_NONE
326 ssl.CERT_OPTIONAL
327 ssl.CERT_REQUIRED
Antoine Pitrou6db49442011-12-19 13:27:11 +0100328 ssl.OP_CIPHER_SERVER_PREFERENCE
Antoine Pitrou0e576f12011-12-22 10:03:38 +0100329 ssl.OP_SINGLE_DH_USE
Christian Heimesd37b74f2021-04-19 08:31:29 +0200330 ssl.OP_SINGLE_ECDH_USE
Christian Heimes39258d32021-04-17 11:36:35 +0200331 ssl.OP_NO_COMPRESSION
Christian Heimesd37b74f2021-04-19 08:31:29 +0200332 self.assertEqual(ssl.HAS_SNI, True)
333 self.assertEqual(ssl.HAS_ECDH, True)
334 self.assertEqual(ssl.HAS_TLSv1_2, True)
335 self.assertEqual(ssl.HAS_TLSv1_3, True)
Christian Heimescb5b68a2017-09-07 18:07:00 -0700336 ssl.OP_NO_SSLv2
337 ssl.OP_NO_SSLv3
338 ssl.OP_NO_TLSv1
339 ssl.OP_NO_TLSv1_3
Christian Heimes39258d32021-04-17 11:36:35 +0200340 ssl.OP_NO_TLSv1_1
341 ssl.OP_NO_TLSv1_2
Christian Heimesa170fa12017-09-15 20:27:30 +0200342 self.assertEqual(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv23)
Thomas Woutersed03b412007-08-28 21:37:11 +0000343
Christian Heimes9d50ab52018-02-27 10:17:30 +0100344 def test_private_init(self):
345 with self.assertRaisesRegex(TypeError, "public constructor"):
346 with socket.socket() as s:
347 ssl.SSLSocket(s)
348
Antoine Pitrou172f0252014-04-18 20:33:08 +0200349 def test_str_for_enums(self):
350 # Make sure that the PROTOCOL_* constants have enum-like string
351 # reprs.
Christian Heimes2875c602021-04-19 07:27:10 +0200352 proto = ssl.PROTOCOL_TLS_CLIENT
353 self.assertEqual(str(proto), 'PROTOCOL_TLS_CLIENT')
Antoine Pitrou172f0252014-04-18 20:33:08 +0200354 ctx = ssl.SSLContext(proto)
355 self.assertIs(ctx.protocol, proto)
356
Antoine Pitrou480a1242010-04-28 21:37:09 +0000357 def test_random(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000358 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000359 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000360 sys.stdout.write("\n RAND_status is %d (%s)\n"
361 % (v, (v and "sufficient randomness") or
362 "insufficient randomness"))
Victor Stinner99c8b162011-05-24 12:05:19 +0200363
Christian Heimes2875c602021-04-19 07:27:10 +0200364 with warnings_helper.check_warnings():
365 data, is_cryptographic = ssl.RAND_pseudo_bytes(16)
Victor Stinner99c8b162011-05-24 12:05:19 +0200366 self.assertEqual(len(data), 16)
367 self.assertEqual(is_cryptographic, v == 1)
368 if v:
369 data = ssl.RAND_bytes(16)
370 self.assertEqual(len(data), 16)
Victor Stinner2e2baa92011-05-25 11:15:16 +0200371 else:
372 self.assertRaises(ssl.SSLError, ssl.RAND_bytes, 16)
Victor Stinner99c8b162011-05-24 12:05:19 +0200373
Victor Stinner1e81a392013-12-19 16:47:04 +0100374 # negative num is invalid
375 self.assertRaises(ValueError, ssl.RAND_bytes, -5)
Christian Heimes2875c602021-04-19 07:27:10 +0200376 with warnings_helper.check_warnings():
377 self.assertRaises(ValueError, ssl.RAND_pseudo_bytes, -5)
Victor Stinner1e81a392013-12-19 16:47:04 +0100378
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000379 ssl.RAND_add("this is a random string", 75.0)
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200380 ssl.RAND_add(b"this is a random bytes object", 75.0)
381 ssl.RAND_add(bytearray(b"this is a random bytearray object"), 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +0000382
Antoine Pitrou480a1242010-04-28 21:37:09 +0000383 def test_parse_cert(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000384 # note that this uses an 'unofficial' function in _ssl.c,
385 # provided solely for this test, to exercise the certificate
386 # parsing code
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100387 self.assertEqual(
388 ssl._ssl._test_decode_cert(CERTFILE),
389 CERTFILE_INFO
390 )
391 self.assertEqual(
392 ssl._ssl._test_decode_cert(SIGNED_CERTFILE),
393 SIGNED_CERTFILE_INFO
394 )
395
Antoine Pitroud8c347a2011-10-01 19:20:25 +0200396 # Issue #13034: the subjectAltName in some certificates
397 # (notably projects.developer.nokia.com:443) wasn't parsed
398 p = ssl._ssl._test_decode_cert(NOKIACERT)
399 if support.verbose:
400 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
401 self.assertEqual(p['subjectAltName'],
402 (('DNS', 'projects.developer.nokia.com'),
403 ('DNS', 'projects.forum.nokia.com'))
404 )
Christian Heimesbd3a7f92013-11-21 03:40:15 +0100405 # extra OCSP and AIA fields
406 self.assertEqual(p['OCSP'], ('http://ocsp.verisign.com',))
407 self.assertEqual(p['caIssuers'],
408 ('http://SVRIntl-G3-aia.verisign.com/SVRIntlG3.cer',))
409 self.assertEqual(p['crlDistributionPoints'],
410 ('http://SVRIntl-G3-crl.verisign.com/SVRIntlG3.crl',))
Thomas Woutersed03b412007-08-28 21:37:11 +0000411
Christian Heimesa37f5242019-01-15 23:47:42 +0100412 def test_parse_cert_CVE_2019_5010(self):
413 p = ssl._ssl._test_decode_cert(TALOS_INVALID_CRLDP)
414 if support.verbose:
415 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
416 self.assertEqual(
417 p,
418 {
419 'issuer': (
420 (('countryName', 'UK'),), (('commonName', 'cody-ca'),)),
421 'notAfter': 'Jun 14 18:00:58 2028 GMT',
422 'notBefore': 'Jun 18 18:00:58 2018 GMT',
423 'serialNumber': '02',
424 'subject': ((('countryName', 'UK'),),
425 (('commonName',
426 'codenomicon-vm-2.test.lal.cisco.com'),)),
427 'subjectAltName': (
428 ('DNS', 'codenomicon-vm-2.test.lal.cisco.com'),),
429 'version': 3
430 }
431 )
432
Christian Heimes824f7f32013-08-17 00:54:47 +0200433 def test_parse_cert_CVE_2013_4238(self):
434 p = ssl._ssl._test_decode_cert(NULLBYTECERT)
435 if support.verbose:
436 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
437 subject = ((('countryName', 'US'),),
438 (('stateOrProvinceName', 'Oregon'),),
439 (('localityName', 'Beaverton'),),
440 (('organizationName', 'Python Software Foundation'),),
441 (('organizationalUnitName', 'Python Core Development'),),
442 (('commonName', 'null.python.org\x00example.org'),),
443 (('emailAddress', 'python-dev@python.org'),))
444 self.assertEqual(p['subject'], subject)
445 self.assertEqual(p['issuer'], subject)
Christian Heimes157c9832013-08-25 14:12:41 +0200446 if ssl._OPENSSL_API_VERSION >= (0, 9, 8):
447 san = (('DNS', 'altnull.python.org\x00example.com'),
448 ('email', 'null@python.org\x00user@example.org'),
449 ('URI', 'http://null.python.org\x00http://example.org'),
450 ('IP Address', '192.0.2.1'),
Christian Heimes2b7de662019-12-07 17:59:36 +0100451 ('IP Address', '2001:DB8:0:0:0:0:0:1'))
Christian Heimes157c9832013-08-25 14:12:41 +0200452 else:
453 # OpenSSL 0.9.7 doesn't support IPv6 addresses in subjectAltName
454 san = (('DNS', 'altnull.python.org\x00example.com'),
455 ('email', 'null@python.org\x00user@example.org'),
456 ('URI', 'http://null.python.org\x00http://example.org'),
457 ('IP Address', '192.0.2.1'),
458 ('IP Address', '<invalid>'))
459
460 self.assertEqual(p['subjectAltName'], san)
Christian Heimes824f7f32013-08-17 00:54:47 +0200461
Christian Heimes1c03abd2016-09-06 23:25:35 +0200462 def test_parse_all_sans(self):
463 p = ssl._ssl._test_decode_cert(ALLSANFILE)
464 self.assertEqual(p['subjectAltName'],
465 (
466 ('DNS', 'allsans'),
467 ('othername', '<unsupported>'),
468 ('othername', '<unsupported>'),
469 ('email', 'user@example.org'),
470 ('DNS', 'www.example.org'),
471 ('DirName',
472 ((('countryName', 'XY'),),
473 (('localityName', 'Castle Anthrax'),),
474 (('organizationName', 'Python Software Foundation'),),
475 (('commonName', 'dirname example'),))),
476 ('URI', 'https://www.python.org/'),
477 ('IP Address', '127.0.0.1'),
Christian Heimes2b7de662019-12-07 17:59:36 +0100478 ('IP Address', '0:0:0:0:0:0:0:1'),
Christian Heimes1c03abd2016-09-06 23:25:35 +0200479 ('Registered ID', '1.2.3.4.5')
480 )
481 )
482
Antoine Pitrou480a1242010-04-28 21:37:09 +0000483 def test_DER_to_PEM(self):
Martin Panter3d81d932016-01-14 09:36:00 +0000484 with open(CAFILE_CACERT, 'r') as f:
Antoine Pitrou480a1242010-04-28 21:37:09 +0000485 pem = f.read()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000486 d1 = ssl.PEM_cert_to_DER_cert(pem)
487 p2 = ssl.DER_cert_to_PEM_cert(d1)
488 d2 = ssl.PEM_cert_to_DER_cert(p2)
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000489 self.assertEqual(d1, d2)
Antoine Pitrou9bfbe612010-04-27 22:08:08 +0000490 if not p2.startswith(ssl.PEM_HEADER + '\n'):
491 self.fail("DER-to-PEM didn't include correct header:\n%r\n" % p2)
492 if not p2.endswith('\n' + ssl.PEM_FOOTER + '\n'):
493 self.fail("DER-to-PEM didn't include correct footer:\n%r\n" % p2)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000494
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000495 def test_openssl_version(self):
496 n = ssl.OPENSSL_VERSION_NUMBER
497 t = ssl.OPENSSL_VERSION_INFO
498 s = ssl.OPENSSL_VERSION
499 self.assertIsInstance(n, int)
500 self.assertIsInstance(t, tuple)
501 self.assertIsInstance(s, str)
502 # Some sanity checks follow
Christian Heimesd37b74f2021-04-19 08:31:29 +0200503 # >= 1.1.1
504 self.assertGreaterEqual(n, 0x10101000)
Christian Heimes2b7de662019-12-07 17:59:36 +0100505 # < 4.0
506 self.assertLess(n, 0x40000000)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000507 major, minor, fix, patch, status = t
Christian Heimes2b7de662019-12-07 17:59:36 +0100508 self.assertGreaterEqual(major, 1)
509 self.assertLess(major, 4)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000510 self.assertGreaterEqual(minor, 0)
511 self.assertLess(minor, 256)
512 self.assertGreaterEqual(fix, 0)
513 self.assertLess(fix, 256)
514 self.assertGreaterEqual(patch, 0)
Ned Deily05784a72015-02-05 17:20:13 +1100515 self.assertLessEqual(patch, 63)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000516 self.assertGreaterEqual(status, 0)
517 self.assertLessEqual(status, 15)
Christian Heimesd37b74f2021-04-19 08:31:29 +0200518
519 libressl_ver = f"LibreSSL {major:d}"
520 openssl_ver = f"OpenSSL {major:d}.{minor:d}.{fix:d}"
521 self.assertTrue(
522 s.startswith((openssl_ver, libressl_ver)),
523 (s, t, hex(n))
524 )
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000525
Antoine Pitrou9d543662010-04-23 23:10:32 +0000526 @support.cpython_only
527 def test_refcycle(self):
528 # Issue #7943: an SSL object doesn't create reference cycles with
529 # itself.
530 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200531 ss = test_wrap_socket(s)
Antoine Pitrou9d543662010-04-23 23:10:32 +0000532 wr = weakref.ref(ss)
Hai Shia7f5d932020-08-04 00:41:24 +0800533 with warnings_helper.check_warnings(("", ResourceWarning)):
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100534 del ss
Victor Stinnere0b75b72016-03-21 17:26:04 +0100535 self.assertEqual(wr(), None)
Antoine Pitrou9d543662010-04-23 23:10:32 +0000536
Antoine Pitroua468adc2010-09-14 14:43:44 +0000537 def test_wrapped_unconnected(self):
538 # Methods on an unconnected SSLSocket propagate the original
Andrew Svetlov0832af62012-12-18 23:10:48 +0200539 # OSError raise by the underlying socket object.
Antoine Pitroua468adc2010-09-14 14:43:44 +0000540 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200541 with test_wrap_socket(s) as ss:
Antoine Pitroue9bb4732013-01-12 21:56:56 +0100542 self.assertRaises(OSError, ss.recv, 1)
543 self.assertRaises(OSError, ss.recv_into, bytearray(b'x'))
544 self.assertRaises(OSError, ss.recvfrom, 1)
545 self.assertRaises(OSError, ss.recvfrom_into, bytearray(b'x'), 1)
546 self.assertRaises(OSError, ss.send, b'x')
547 self.assertRaises(OSError, ss.sendto, b'x', ('0.0.0.0', 0))
Serhiy Storchaka42b1d612018-12-06 22:36:55 +0200548 self.assertRaises(NotImplementedError, ss.dup)
Christian Heimes141c5e82018-02-24 21:10:57 +0100549 self.assertRaises(NotImplementedError, ss.sendmsg,
550 [b'x'], (), 0, ('0.0.0.0', 0))
Serhiy Storchaka42b1d612018-12-06 22:36:55 +0200551 self.assertRaises(NotImplementedError, ss.recvmsg, 100)
552 self.assertRaises(NotImplementedError, ss.recvmsg_into,
553 [bytearray(100)])
Antoine Pitroua468adc2010-09-14 14:43:44 +0000554
Antoine Pitrou40f08742010-04-24 22:04:40 +0000555 def test_timeout(self):
556 # Issue #8524: when creating an SSL socket, the timeout of the
557 # original socket should be retained.
558 for timeout in (None, 0.0, 5.0):
559 s = socket.socket(socket.AF_INET)
560 s.settimeout(timeout)
Christian Heimesd0486372016-09-10 23:23:33 +0200561 with test_wrap_socket(s) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100562 self.assertEqual(timeout, ss.gettimeout())
Antoine Pitrou40f08742010-04-24 22:04:40 +0000563
Christian Heimes2875c602021-04-19 07:27:10 +0200564 @ignore_deprecation
Christian Heimesd0486372016-09-10 23:23:33 +0200565 def test_errors_sslwrap(self):
Giampaolo Rodolà745ab382010-08-29 19:25:49 +0000566 sock = socket.socket()
Ezio Melottied3a7d22010-12-01 02:32:32 +0000567 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000568 "certfile must be specified",
569 ssl.wrap_socket, sock, keyfile=CERTFILE)
Ezio Melottied3a7d22010-12-01 02:32:32 +0000570 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000571 "certfile must be specified for server-side operations",
572 ssl.wrap_socket, sock, server_side=True)
Ezio Melottied3a7d22010-12-01 02:32:32 +0000573 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000574 "certfile must be specified for server-side operations",
Christian Heimesd0486372016-09-10 23:23:33 +0200575 ssl.wrap_socket, sock, server_side=True, certfile="")
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100576 with ssl.wrap_socket(sock, server_side=True, certfile=CERTFILE) as s:
577 self.assertRaisesRegex(ValueError, "can't connect in server-side mode",
Christian Heimesd0486372016-09-10 23:23:33 +0200578 s.connect, (HOST, 8080))
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200579 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000580 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000581 ssl.wrap_socket(sock, certfile=NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +0000582 self.assertEqual(cm.exception.errno, errno.ENOENT)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200583 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000584 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000585 ssl.wrap_socket(sock,
586 certfile=CERTFILE, keyfile=NONEXISTINGCERT)
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000587 self.assertEqual(cm.exception.errno, errno.ENOENT)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200588 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000589 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000590 ssl.wrap_socket(sock,
591 certfile=NONEXISTINGCERT, keyfile=NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +0000592 self.assertEqual(cm.exception.errno, errno.ENOENT)
Giampaolo Rodolà745ab382010-08-29 19:25:49 +0000593
Martin Panter3464ea22016-02-01 21:58:11 +0000594 def bad_cert_test(self, certfile):
595 """Check that trying to use the given client certificate fails"""
596 certfile = os.path.join(os.path.dirname(__file__) or os.curdir,
597 certfile)
598 sock = socket.socket()
599 self.addCleanup(sock.close)
600 with self.assertRaises(ssl.SSLError):
Christian Heimesd0486372016-09-10 23:23:33 +0200601 test_wrap_socket(sock,
Christian Heimesa170fa12017-09-15 20:27:30 +0200602 certfile=certfile)
Martin Panter3464ea22016-02-01 21:58:11 +0000603
604 def test_empty_cert(self):
605 """Wrapping with an empty cert file"""
606 self.bad_cert_test("nullcert.pem")
607
608 def test_malformed_cert(self):
609 """Wrapping with a badly formatted certificate (syntax error)"""
610 self.bad_cert_test("badcert.pem")
611
612 def test_malformed_key(self):
613 """Wrapping with a badly formatted key (syntax error)"""
614 self.bad_cert_test("badkey.pem")
615
Christian Heimes2875c602021-04-19 07:27:10 +0200616 @ignore_deprecation
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000617 def test_match_hostname(self):
618 def ok(cert, hostname):
619 ssl.match_hostname(cert, hostname)
620 def fail(cert, hostname):
621 self.assertRaises(ssl.CertificateError,
622 ssl.match_hostname, cert, hostname)
623
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100624 # -- Hostname matching --
625
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000626 cert = {'subject': ((('commonName', 'example.com'),),)}
627 ok(cert, 'example.com')
628 ok(cert, 'ExAmple.cOm')
629 fail(cert, 'www.example.com')
630 fail(cert, '.example.com')
631 fail(cert, 'example.org')
632 fail(cert, 'exampleXcom')
633
634 cert = {'subject': ((('commonName', '*.a.com'),),)}
635 ok(cert, 'foo.a.com')
636 fail(cert, 'bar.foo.a.com')
637 fail(cert, 'a.com')
638 fail(cert, 'Xa.com')
639 fail(cert, '.a.com')
640
Mandeep Singhede2ac92017-11-27 04:01:27 +0530641 # only match wildcards when they are the only thing
642 # in left-most segment
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000643 cert = {'subject': ((('commonName', 'f*.com'),),)}
Mandeep Singhede2ac92017-11-27 04:01:27 +0530644 fail(cert, 'foo.com')
645 fail(cert, 'f.com')
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000646 fail(cert, 'bar.com')
647 fail(cert, 'foo.a.com')
648 fail(cert, 'bar.foo.com')
649
Christian Heimes824f7f32013-08-17 00:54:47 +0200650 # NULL bytes are bad, CVE-2013-4073
651 cert = {'subject': ((('commonName',
652 'null.python.org\x00example.org'),),)}
653 ok(cert, 'null.python.org\x00example.org') # or raise an error?
654 fail(cert, 'example.org')
655 fail(cert, 'null.python.org')
656
Georg Brandl72c98d32013-10-27 07:16:53 +0100657 # error cases with wildcards
658 cert = {'subject': ((('commonName', '*.*.a.com'),),)}
659 fail(cert, 'bar.foo.a.com')
660 fail(cert, 'a.com')
661 fail(cert, 'Xa.com')
662 fail(cert, '.a.com')
663
664 cert = {'subject': ((('commonName', 'a.*.com'),),)}
665 fail(cert, 'a.foo.com')
666 fail(cert, 'a..com')
667 fail(cert, 'a.com')
668
669 # wildcard doesn't match IDNA prefix 'xn--'
670 idna = 'püthon.python.org'.encode("idna").decode("ascii")
671 cert = {'subject': ((('commonName', idna),),)}
672 ok(cert, idna)
673 cert = {'subject': ((('commonName', 'x*.python.org'),),)}
674 fail(cert, idna)
675 cert = {'subject': ((('commonName', 'xn--p*.python.org'),),)}
676 fail(cert, idna)
677
678 # wildcard in first fragment and IDNA A-labels in sequent fragments
679 # are supported.
680 idna = 'www*.pythön.org'.encode("idna").decode("ascii")
681 cert = {'subject': ((('commonName', idna),),)}
Mandeep Singhede2ac92017-11-27 04:01:27 +0530682 fail(cert, 'www.pythön.org'.encode("idna").decode("ascii"))
683 fail(cert, 'www1.pythön.org'.encode("idna").decode("ascii"))
Georg Brandl72c98d32013-10-27 07:16:53 +0100684 fail(cert, 'ftp.pythön.org'.encode("idna").decode("ascii"))
685 fail(cert, 'pythön.org'.encode("idna").decode("ascii"))
686
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000687 # Slightly fake real-world example
688 cert = {'notAfter': 'Jun 26 21:41:46 2011 GMT',
689 'subject': ((('commonName', 'linuxfrz.org'),),),
690 'subjectAltName': (('DNS', 'linuxfr.org'),
691 ('DNS', 'linuxfr.com'),
692 ('othername', '<unsupported>'))}
693 ok(cert, 'linuxfr.org')
694 ok(cert, 'linuxfr.com')
695 # Not a "DNS" entry
696 fail(cert, '<unsupported>')
697 # When there is a subjectAltName, commonName isn't used
698 fail(cert, 'linuxfrz.org')
699
700 # A pristine real-world example
701 cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT',
702 'subject': ((('countryName', 'US'),),
703 (('stateOrProvinceName', 'California'),),
704 (('localityName', 'Mountain View'),),
705 (('organizationName', 'Google Inc'),),
706 (('commonName', 'mail.google.com'),))}
707 ok(cert, 'mail.google.com')
708 fail(cert, 'gmail.com')
709 # Only commonName is considered
710 fail(cert, 'California')
711
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100712 # -- IPv4 matching --
713 cert = {'subject': ((('commonName', 'example.com'),),),
714 'subjectAltName': (('DNS', 'example.com'),
715 ('IP Address', '10.11.12.13'),
Christian Heimes477b1b22019-07-02 20:39:42 +0200716 ('IP Address', '14.15.16.17'),
717 ('IP Address', '127.0.0.1'))}
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100718 ok(cert, '10.11.12.13')
719 ok(cert, '14.15.16.17')
Christian Heimes477b1b22019-07-02 20:39:42 +0200720 # socket.inet_ntoa(socket.inet_aton('127.1')) == '127.0.0.1'
721 fail(cert, '127.1')
722 fail(cert, '14.15.16.17 ')
723 fail(cert, '14.15.16.17 extra data')
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100724 fail(cert, '14.15.16.18')
725 fail(cert, 'example.net')
726
727 # -- IPv6 matching --
Serhiy Storchaka16994912020-04-25 10:06:29 +0300728 if socket_helper.IPV6_ENABLED:
Christian Heimesaef12832018-02-24 14:35:56 +0100729 cert = {'subject': ((('commonName', 'example.com'),),),
730 'subjectAltName': (
731 ('DNS', 'example.com'),
732 ('IP Address', '2001:0:0:0:0:0:0:CAFE\n'),
733 ('IP Address', '2003:0:0:0:0:0:0:BABA\n'))}
734 ok(cert, '2001::cafe')
735 ok(cert, '2003::baba')
Christian Heimes477b1b22019-07-02 20:39:42 +0200736 fail(cert, '2003::baba ')
737 fail(cert, '2003::baba extra data')
Christian Heimesaef12832018-02-24 14:35:56 +0100738 fail(cert, '2003::bebe')
739 fail(cert, 'example.net')
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100740
741 # -- Miscellaneous --
742
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000743 # Neither commonName nor subjectAltName
744 cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT',
745 'subject': ((('countryName', 'US'),),
746 (('stateOrProvinceName', 'California'),),
747 (('localityName', 'Mountain View'),),
748 (('organizationName', 'Google Inc'),))}
749 fail(cert, 'mail.google.com')
750
Antoine Pitrou1c86b442011-05-06 15:19:49 +0200751 # No DNS entry in subjectAltName but a commonName
752 cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT',
753 'subject': ((('countryName', 'US'),),
754 (('stateOrProvinceName', 'California'),),
755 (('localityName', 'Mountain View'),),
756 (('commonName', 'mail.google.com'),)),
757 'subjectAltName': (('othername', 'blabla'), )}
758 ok(cert, 'mail.google.com')
759
760 # No DNS entry subjectAltName and no commonName
761 cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT',
762 'subject': ((('countryName', 'US'),),
763 (('stateOrProvinceName', 'California'),),
764 (('localityName', 'Mountain View'),),
765 (('organizationName', 'Google Inc'),)),
766 'subjectAltName': (('othername', 'blabla'),)}
767 fail(cert, 'google.com')
768
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000769 # Empty cert / no cert
770 self.assertRaises(ValueError, ssl.match_hostname, None, 'example.com')
771 self.assertRaises(ValueError, ssl.match_hostname, {}, 'example.com')
772
Antoine Pitrou636f93c2013-05-18 17:56:42 +0200773 # Issue #17980: avoid denials of service by refusing more than one
774 # wildcard per fragment.
Christian Heimesaef12832018-02-24 14:35:56 +0100775 cert = {'subject': ((('commonName', 'a*b.example.com'),),)}
776 with self.assertRaisesRegex(
777 ssl.CertificateError,
778 "partial wildcards in leftmost label are not supported"):
779 ssl.match_hostname(cert, 'axxb.example.com')
780
781 cert = {'subject': ((('commonName', 'www.*.example.com'),),)}
782 with self.assertRaisesRegex(
783 ssl.CertificateError,
784 "wildcard can only be present in the leftmost label"):
785 ssl.match_hostname(cert, 'www.sub.example.com')
786
787 cert = {'subject': ((('commonName', 'a*b*.example.com'),),)}
788 with self.assertRaisesRegex(
789 ssl.CertificateError,
790 "too many wildcards"):
791 ssl.match_hostname(cert, 'axxbxxc.example.com')
792
793 cert = {'subject': ((('commonName', '*'),),)}
794 with self.assertRaisesRegex(
795 ssl.CertificateError,
796 "sole wildcard without additional labels are not support"):
797 ssl.match_hostname(cert, 'host')
798
799 cert = {'subject': ((('commonName', '*.com'),),)}
800 with self.assertRaisesRegex(
801 ssl.CertificateError,
802 r"hostname 'com' doesn't match '\*.com'"):
803 ssl.match_hostname(cert, 'com')
804
805 # extra checks for _inet_paton()
806 for invalid in ['1', '', '1.2.3', '256.0.0.1', '127.0.0.1/24']:
807 with self.assertRaises(ValueError):
808 ssl._inet_paton(invalid)
809 for ipaddr in ['127.0.0.1', '192.168.0.1']:
810 self.assertTrue(ssl._inet_paton(ipaddr))
Serhiy Storchaka16994912020-04-25 10:06:29 +0300811 if socket_helper.IPV6_ENABLED:
Christian Heimesaef12832018-02-24 14:35:56 +0100812 for ipaddr in ['::1', '2001:db8:85a3::8a2e:370:7334']:
813 self.assertTrue(ssl._inet_paton(ipaddr))
Antoine Pitrou636f93c2013-05-18 17:56:42 +0200814
Antoine Pitroud5323212010-10-22 18:19:07 +0000815 def test_server_side(self):
816 # server_hostname doesn't work for server sockets
Christian Heimesa170fa12017-09-15 20:27:30 +0200817 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroud2eca372010-10-29 23:41:37 +0000818 with socket.socket() as sock:
819 self.assertRaises(ValueError, ctx.wrap_socket, sock, True,
820 server_hostname="some.hostname")
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000821
Antoine Pitroud6494802011-07-21 01:11:30 +0200822 def test_unknown_channel_binding(self):
823 # should raise ValueError for unknown type
Giampaolo Rodolaeb7e29f2019-04-09 00:34:02 +0200824 s = socket.create_server(('127.0.0.1', 0))
Antoine Pitroub1fdf472014-10-05 20:41:53 +0200825 c = socket.socket(socket.AF_INET)
826 c.connect(s.getsockname())
Christian Heimesd0486372016-09-10 23:23:33 +0200827 with test_wrap_socket(c, do_handshake_on_connect=False) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100828 with self.assertRaises(ValueError):
829 ss.get_channel_binding("unknown-type")
Antoine Pitroub1fdf472014-10-05 20:41:53 +0200830 s.close()
Antoine Pitroud6494802011-07-21 01:11:30 +0200831
832 @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES,
833 "'tls-unique' channel binding not available")
834 def test_tls_unique_channel_binding(self):
835 # unconnected should return None for known type
836 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200837 with test_wrap_socket(s) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100838 self.assertIsNone(ss.get_channel_binding("tls-unique"))
Antoine Pitroud6494802011-07-21 01:11:30 +0200839 # the same for server-side
840 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200841 with test_wrap_socket(s, server_side=True, certfile=CERTFILE) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100842 self.assertIsNone(ss.get_channel_binding("tls-unique"))
Antoine Pitroud6494802011-07-21 01:11:30 +0200843
Benjamin Peterson36f7b972013-01-10 14:16:20 -0600844 def test_dealloc_warn(self):
Christian Heimesd0486372016-09-10 23:23:33 +0200845 ss = test_wrap_socket(socket.socket(socket.AF_INET))
Benjamin Peterson36f7b972013-01-10 14:16:20 -0600846 r = repr(ss)
847 with self.assertWarns(ResourceWarning) as cm:
848 ss = None
849 support.gc_collect()
850 self.assertIn(r, str(cm.warning.args[0]))
851
Christian Heimes6d7ad132013-06-09 18:02:55 +0200852 def test_get_default_verify_paths(self):
853 paths = ssl.get_default_verify_paths()
854 self.assertEqual(len(paths), 6)
855 self.assertIsInstance(paths, ssl.DefaultVerifyPaths)
856
Hai Shia7f5d932020-08-04 00:41:24 +0800857 with os_helper.EnvironmentVarGuard() as env:
Christian Heimes6d7ad132013-06-09 18:02:55 +0200858 env["SSL_CERT_DIR"] = CAPATH
859 env["SSL_CERT_FILE"] = CERTFILE
860 paths = ssl.get_default_verify_paths()
861 self.assertEqual(paths.cafile, CERTFILE)
862 self.assertEqual(paths.capath, CAPATH)
863
Christian Heimes44109d72013-11-22 01:51:30 +0100864 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
865 def test_enum_certificates(self):
866 self.assertTrue(ssl.enum_certificates("CA"))
867 self.assertTrue(ssl.enum_certificates("ROOT"))
868
869 self.assertRaises(TypeError, ssl.enum_certificates)
870 self.assertRaises(WindowsError, ssl.enum_certificates, "")
871
Christian Heimesc2d65e12013-11-22 16:13:55 +0100872 trust_oids = set()
873 for storename in ("CA", "ROOT"):
874 store = ssl.enum_certificates(storename)
875 self.assertIsInstance(store, list)
876 for element in store:
877 self.assertIsInstance(element, tuple)
878 self.assertEqual(len(element), 3)
879 cert, enc, trust = element
880 self.assertIsInstance(cert, bytes)
881 self.assertIn(enc, {"x509_asn", "pkcs_7_asn"})
Christian Heimes915cd3f2019-09-09 18:06:55 +0200882 self.assertIsInstance(trust, (frozenset, set, bool))
883 if isinstance(trust, (frozenset, set)):
Christian Heimesc2d65e12013-11-22 16:13:55 +0100884 trust_oids.update(trust)
Christian Heimes44109d72013-11-22 01:51:30 +0100885
886 serverAuth = "1.3.6.1.5.5.7.3.1"
Christian Heimesc2d65e12013-11-22 16:13:55 +0100887 self.assertIn(serverAuth, trust_oids)
Christian Heimes6d7ad132013-06-09 18:02:55 +0200888
Christian Heimes46bebee2013-06-09 19:03:31 +0200889 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
Christian Heimes44109d72013-11-22 01:51:30 +0100890 def test_enum_crls(self):
891 self.assertTrue(ssl.enum_crls("CA"))
892 self.assertRaises(TypeError, ssl.enum_crls)
893 self.assertRaises(WindowsError, ssl.enum_crls, "")
Christian Heimes46bebee2013-06-09 19:03:31 +0200894
Christian Heimes44109d72013-11-22 01:51:30 +0100895 crls = ssl.enum_crls("CA")
896 self.assertIsInstance(crls, list)
897 for element in crls:
898 self.assertIsInstance(element, tuple)
899 self.assertEqual(len(element), 2)
900 self.assertIsInstance(element[0], bytes)
901 self.assertIn(element[1], {"x509_asn", "pkcs_7_asn"})
Christian Heimes46bebee2013-06-09 19:03:31 +0200902
Christian Heimes46bebee2013-06-09 19:03:31 +0200903
Christian Heimesa6bc95a2013-11-17 19:59:14 +0100904 def test_asn1object(self):
905 expected = (129, 'serverAuth', 'TLS Web Server Authentication',
906 '1.3.6.1.5.5.7.3.1')
907
908 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1')
909 self.assertEqual(val, expected)
910 self.assertEqual(val.nid, 129)
911 self.assertEqual(val.shortname, 'serverAuth')
912 self.assertEqual(val.longname, 'TLS Web Server Authentication')
913 self.assertEqual(val.oid, '1.3.6.1.5.5.7.3.1')
914 self.assertIsInstance(val, ssl._ASN1Object)
915 self.assertRaises(ValueError, ssl._ASN1Object, 'serverAuth')
916
917 val = ssl._ASN1Object.fromnid(129)
918 self.assertEqual(val, expected)
919 self.assertIsInstance(val, ssl._ASN1Object)
920 self.assertRaises(ValueError, ssl._ASN1Object.fromnid, -1)
Christian Heimes5398e1a2013-11-22 16:20:53 +0100921 with self.assertRaisesRegex(ValueError, "unknown NID 100000"):
922 ssl._ASN1Object.fromnid(100000)
Christian Heimesa6bc95a2013-11-17 19:59:14 +0100923 for i in range(1000):
924 try:
925 obj = ssl._ASN1Object.fromnid(i)
926 except ValueError:
927 pass
928 else:
929 self.assertIsInstance(obj.nid, int)
930 self.assertIsInstance(obj.shortname, str)
931 self.assertIsInstance(obj.longname, str)
932 self.assertIsInstance(obj.oid, (str, type(None)))
933
934 val = ssl._ASN1Object.fromname('TLS Web Server Authentication')
935 self.assertEqual(val, expected)
936 self.assertIsInstance(val, ssl._ASN1Object)
937 self.assertEqual(ssl._ASN1Object.fromname('serverAuth'), expected)
938 self.assertEqual(ssl._ASN1Object.fromname('1.3.6.1.5.5.7.3.1'),
939 expected)
Christian Heimes5398e1a2013-11-22 16:20:53 +0100940 with self.assertRaisesRegex(ValueError, "unknown object 'serverauth'"):
941 ssl._ASN1Object.fromname('serverauth')
Christian Heimesa6bc95a2013-11-17 19:59:14 +0100942
Christian Heimes72d28502013-11-23 13:56:58 +0100943 def test_purpose_enum(self):
944 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1')
945 self.assertIsInstance(ssl.Purpose.SERVER_AUTH, ssl._ASN1Object)
946 self.assertEqual(ssl.Purpose.SERVER_AUTH, val)
947 self.assertEqual(ssl.Purpose.SERVER_AUTH.nid, 129)
948 self.assertEqual(ssl.Purpose.SERVER_AUTH.shortname, 'serverAuth')
949 self.assertEqual(ssl.Purpose.SERVER_AUTH.oid,
950 '1.3.6.1.5.5.7.3.1')
951
952 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.2')
953 self.assertIsInstance(ssl.Purpose.CLIENT_AUTH, ssl._ASN1Object)
954 self.assertEqual(ssl.Purpose.CLIENT_AUTH, val)
955 self.assertEqual(ssl.Purpose.CLIENT_AUTH.nid, 130)
956 self.assertEqual(ssl.Purpose.CLIENT_AUTH.shortname, 'clientAuth')
957 self.assertEqual(ssl.Purpose.CLIENT_AUTH.oid,
958 '1.3.6.1.5.5.7.3.2')
959
Antoine Pitrou3e86ba42013-12-28 17:26:33 +0100960 def test_unsupported_dtls(self):
961 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
962 self.addCleanup(s.close)
963 with self.assertRaises(NotImplementedError) as cx:
Christian Heimesd0486372016-09-10 23:23:33 +0200964 test_wrap_socket(s, cert_reqs=ssl.CERT_NONE)
Antoine Pitrou3e86ba42013-12-28 17:26:33 +0100965 self.assertEqual(str(cx.exception), "only stream sockets are supported")
Christian Heimesa170fa12017-09-15 20:27:30 +0200966 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou3e86ba42013-12-28 17:26:33 +0100967 with self.assertRaises(NotImplementedError) as cx:
968 ctx.wrap_socket(s)
969 self.assertEqual(str(cx.exception), "only stream sockets are supported")
970
Antoine Pitrouc695c952014-04-28 20:57:36 +0200971 def cert_time_ok(self, timestring, timestamp):
972 self.assertEqual(ssl.cert_time_to_seconds(timestring), timestamp)
973
974 def cert_time_fail(self, timestring):
975 with self.assertRaises(ValueError):
976 ssl.cert_time_to_seconds(timestring)
977
978 @unittest.skipUnless(utc_offset(),
979 'local time needs to be different from UTC')
980 def test_cert_time_to_seconds_timezone(self):
981 # Issue #19940: ssl.cert_time_to_seconds() returns wrong
982 # results if local timezone is not UTC
983 self.cert_time_ok("May 9 00:00:00 2007 GMT", 1178668800.0)
984 self.cert_time_ok("Jan 5 09:34:43 2018 GMT", 1515144883.0)
985
986 def test_cert_time_to_seconds(self):
987 timestring = "Jan 5 09:34:43 2018 GMT"
988 ts = 1515144883.0
989 self.cert_time_ok(timestring, ts)
990 # accept keyword parameter, assert its name
991 self.assertEqual(ssl.cert_time_to_seconds(cert_time=timestring), ts)
992 # accept both %e and %d (space or zero generated by strftime)
993 self.cert_time_ok("Jan 05 09:34:43 2018 GMT", ts)
994 # case-insensitive
995 self.cert_time_ok("JaN 5 09:34:43 2018 GmT", ts)
996 self.cert_time_fail("Jan 5 09:34 2018 GMT") # no seconds
997 self.cert_time_fail("Jan 5 09:34:43 2018") # no GMT
998 self.cert_time_fail("Jan 5 09:34:43 2018 UTC") # not GMT timezone
999 self.cert_time_fail("Jan 35 09:34:43 2018 GMT") # invalid day
1000 self.cert_time_fail("Jon 5 09:34:43 2018 GMT") # invalid month
1001 self.cert_time_fail("Jan 5 24:00:00 2018 GMT") # invalid hour
1002 self.cert_time_fail("Jan 5 09:60:43 2018 GMT") # invalid minute
1003
1004 newyear_ts = 1230768000.0
1005 # leap seconds
1006 self.cert_time_ok("Dec 31 23:59:60 2008 GMT", newyear_ts)
1007 # same timestamp
1008 self.cert_time_ok("Jan 1 00:00:00 2009 GMT", newyear_ts)
1009
1010 self.cert_time_ok("Jan 5 09:34:59 2018 GMT", 1515144899)
1011 # allow 60th second (even if it is not a leap second)
1012 self.cert_time_ok("Jan 5 09:34:60 2018 GMT", 1515144900)
1013 # allow 2nd leap second for compatibility with time.strptime()
1014 self.cert_time_ok("Jan 5 09:34:61 2018 GMT", 1515144901)
1015 self.cert_time_fail("Jan 5 09:34:62 2018 GMT") # invalid seconds
1016
Mike53f7a7c2017-12-14 14:04:53 +03001017 # no special treatment for the special value:
Antoine Pitrouc695c952014-04-28 20:57:36 +02001018 # 99991231235959Z (rfc 5280)
1019 self.cert_time_ok("Dec 31 23:59:59 9999 GMT", 253402300799.0)
1020
1021 @support.run_with_locale('LC_ALL', '')
1022 def test_cert_time_to_seconds_locale(self):
1023 # `cert_time_to_seconds()` should be locale independent
1024
1025 def local_february_name():
1026 return time.strftime('%b', (1, 2, 3, 4, 5, 6, 0, 0, 0))
1027
1028 if local_february_name().lower() == 'feb':
1029 self.skipTest("locale-specific month name needs to be "
1030 "different from C locale")
1031
1032 # locale-independent
1033 self.cert_time_ok("Feb 9 00:00:00 2007 GMT", 1170979200.0)
1034 self.cert_time_fail(local_february_name() + " 9 00:00:00 2007 GMT")
1035
Martin Panter3840b2a2016-03-27 01:53:46 +00001036 def test_connect_ex_error(self):
1037 server = socket.socket(socket.AF_INET)
1038 self.addCleanup(server.close)
Serhiy Storchaka16994912020-04-25 10:06:29 +03001039 port = socket_helper.bind_port(server) # Reserve port but don't listen
Christian Heimesd0486372016-09-10 23:23:33 +02001040 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001041 cert_reqs=ssl.CERT_REQUIRED)
1042 self.addCleanup(s.close)
1043 rc = s.connect_ex((HOST, port))
1044 # Issue #19919: Windows machines or VMs hosted on Windows
1045 # machines sometimes return EWOULDBLOCK.
1046 errors = (
1047 errno.ECONNREFUSED, errno.EHOSTUNREACH, errno.ETIMEDOUT,
1048 errno.EWOULDBLOCK,
1049 )
1050 self.assertIn(rc, errors)
1051
Christian Heimes89d15502021-04-19 06:55:30 +02001052 def test_read_write_zero(self):
1053 # empty reads and writes now work, bpo-42854, bpo-31711
1054 client_context, server_context, hostname = testing_context()
1055 server = ThreadedEchoServer(context=server_context)
1056 with server:
1057 with client_context.wrap_socket(socket.socket(),
1058 server_hostname=hostname) as s:
1059 s.connect((HOST, server.port))
1060 self.assertEqual(s.recv(0), b"")
1061 self.assertEqual(s.send(b""), 0)
1062
Christian Heimesa6bc95a2013-11-17 19:59:14 +01001063
Antoine Pitrou152efa22010-05-16 18:19:27 +00001064class ContextTests(unittest.TestCase):
1065
1066 def test_constructor(self):
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01001067 for protocol in PROTOCOLS:
Christian Heimes2875c602021-04-19 07:27:10 +02001068 with warnings_helper.check_warnings():
1069 ctx = ssl.SSLContext(protocol)
1070 self.assertEqual(ctx.protocol, protocol)
1071 with warnings_helper.check_warnings():
1072 ctx = ssl.SSLContext()
Christian Heimes598894f2016-09-05 23:19:05 +02001073 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001074 self.assertRaises(ValueError, ssl.SSLContext, -1)
1075 self.assertRaises(ValueError, ssl.SSLContext, 42)
1076
Antoine Pitrou152efa22010-05-16 18:19:27 +00001077 def test_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001078 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001079 ctx.set_ciphers("ALL")
1080 ctx.set_ciphers("DEFAULT")
Ezio Melottied3a7d22010-12-01 02:32:32 +00001081 with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
Antoine Pitrou30474062010-05-16 23:46:26 +00001082 ctx.set_ciphers("^$:,;?*'dorothyx")
Antoine Pitrou152efa22010-05-16 18:19:27 +00001083
Christian Heimes892d66e2018-01-29 14:10:18 +01001084 @unittest.skipUnless(PY_SSL_DEFAULT_CIPHERS == 1,
1085 "Test applies only to Python default ciphers")
1086 def test_python_ciphers(self):
1087 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1088 ciphers = ctx.get_ciphers()
1089 for suite in ciphers:
1090 name = suite['name']
1091 self.assertNotIn("PSK", name)
1092 self.assertNotIn("SRP", name)
1093 self.assertNotIn("MD5", name)
1094 self.assertNotIn("RC4", name)
1095 self.assertNotIn("3DES", name)
1096
Christian Heimes25bfcd52016-09-06 00:04:45 +02001097 def test_get_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001098 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesea9b2dc2016-09-06 10:45:44 +02001099 ctx.set_ciphers('AESGCM')
Christian Heimes25bfcd52016-09-06 00:04:45 +02001100 names = set(d['name'] for d in ctx.get_ciphers())
Christian Heimes582282b2016-09-06 11:27:25 +02001101 self.assertIn('AES256-GCM-SHA384', names)
1102 self.assertIn('AES128-GCM-SHA256', names)
Christian Heimes25bfcd52016-09-06 00:04:45 +02001103
Antoine Pitroub5218772010-05-21 09:56:06 +00001104 def test_options(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001105 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Benjamin Petersona9dcdab2015-11-11 22:38:41 -08001106 # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value
Christian Heimes598894f2016-09-05 23:19:05 +02001107 default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
Christian Heimes358cfd42016-09-10 22:43:48 +02001108 # SSLContext also enables these by default
1109 default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE |
Christian Heimes05d9fe32018-02-27 08:55:39 +01001110 OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE |
Christian Heimes6f37ebc2021-04-09 17:59:21 +02001111 OP_ENABLE_MIDDLEBOX_COMPAT |
1112 OP_IGNORE_UNEXPECTED_EOF)
Christian Heimes598894f2016-09-05 23:19:05 +02001113 self.assertEqual(default, ctx.options)
Christian Heimes2875c602021-04-19 07:27:10 +02001114 with warnings_helper.check_warnings():
1115 ctx.options |= ssl.OP_NO_TLSv1
Christian Heimes598894f2016-09-05 23:19:05 +02001116 self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options)
Christian Heimes2875c602021-04-19 07:27:10 +02001117 with warnings_helper.check_warnings():
1118 ctx.options = (ctx.options & ~ssl.OP_NO_TLSv1)
Christian Heimes39258d32021-04-17 11:36:35 +02001119 self.assertEqual(default, ctx.options)
1120 ctx.options = 0
1121 # Ubuntu has OP_NO_SSLv3 forced on by default
1122 self.assertEqual(0, ctx.options & ~ssl.OP_NO_SSLv3)
Antoine Pitroub5218772010-05-21 09:56:06 +00001123
Christian Heimesa170fa12017-09-15 20:27:30 +02001124 def test_verify_mode_protocol(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001125 with warnings_helper.check_warnings():
1126 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001127 # Default value
1128 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1129 ctx.verify_mode = ssl.CERT_OPTIONAL
1130 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1131 ctx.verify_mode = ssl.CERT_REQUIRED
1132 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1133 ctx.verify_mode = ssl.CERT_NONE
1134 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1135 with self.assertRaises(TypeError):
1136 ctx.verify_mode = None
1137 with self.assertRaises(ValueError):
1138 ctx.verify_mode = 42
1139
Christian Heimesa170fa12017-09-15 20:27:30 +02001140 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1141 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1142 self.assertFalse(ctx.check_hostname)
1143
1144 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1145 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1146 self.assertTrue(ctx.check_hostname)
1147
Christian Heimes61d478c2018-01-27 15:51:38 +01001148 def test_hostname_checks_common_name(self):
1149 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1150 self.assertTrue(ctx.hostname_checks_common_name)
1151 if ssl.HAS_NEVER_CHECK_COMMON_NAME:
1152 ctx.hostname_checks_common_name = True
1153 self.assertTrue(ctx.hostname_checks_common_name)
1154 ctx.hostname_checks_common_name = False
1155 self.assertFalse(ctx.hostname_checks_common_name)
1156 ctx.hostname_checks_common_name = True
1157 self.assertTrue(ctx.hostname_checks_common_name)
1158 else:
1159 with self.assertRaises(AttributeError):
1160 ctx.hostname_checks_common_name = True
Christian Heimesa170fa12017-09-15 20:27:30 +02001161
Christian Heimes2875c602021-04-19 07:27:10 +02001162 @ignore_deprecation
Christian Heimes698dde12018-02-27 11:54:43 +01001163 def test_min_max_version(self):
1164 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimes34de2d32019-01-18 16:09:30 +01001165 # OpenSSL default is MINIMUM_SUPPORTED, however some vendors like
1166 # Fedora override the setting to TLS 1.0.
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001167 minimum_range = {
1168 # stock OpenSSL
1169 ssl.TLSVersion.MINIMUM_SUPPORTED,
1170 # Fedora 29 uses TLS 1.0 by default
1171 ssl.TLSVersion.TLSv1,
1172 # RHEL 8 uses TLS 1.2 by default
1173 ssl.TLSVersion.TLSv1_2
1174 }
torsava34864d12019-12-02 17:15:42 +01001175 maximum_range = {
1176 # stock OpenSSL
1177 ssl.TLSVersion.MAXIMUM_SUPPORTED,
1178 # Fedora 32 uses TLS 1.3 by default
1179 ssl.TLSVersion.TLSv1_3
1180 }
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001181
Christian Heimes34de2d32019-01-18 16:09:30 +01001182 self.assertIn(
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001183 ctx.minimum_version, minimum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001184 )
torsava34864d12019-12-02 17:15:42 +01001185 self.assertIn(
1186 ctx.maximum_version, maximum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001187 )
1188
1189 ctx.minimum_version = ssl.TLSVersion.TLSv1_1
1190 ctx.maximum_version = ssl.TLSVersion.TLSv1_2
1191 self.assertEqual(
1192 ctx.minimum_version, ssl.TLSVersion.TLSv1_1
1193 )
1194 self.assertEqual(
1195 ctx.maximum_version, ssl.TLSVersion.TLSv1_2
1196 )
1197
1198 ctx.minimum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1199 ctx.maximum_version = ssl.TLSVersion.TLSv1
1200 self.assertEqual(
1201 ctx.minimum_version, ssl.TLSVersion.MINIMUM_SUPPORTED
1202 )
1203 self.assertEqual(
1204 ctx.maximum_version, ssl.TLSVersion.TLSv1
1205 )
1206
1207 ctx.maximum_version = ssl.TLSVersion.MAXIMUM_SUPPORTED
1208 self.assertEqual(
1209 ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED
1210 )
1211
1212 ctx.maximum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1213 self.assertIn(
1214 ctx.maximum_version,
1215 {ssl.TLSVersion.TLSv1, ssl.TLSVersion.SSLv3}
1216 )
1217
1218 ctx.minimum_version = ssl.TLSVersion.MAXIMUM_SUPPORTED
1219 self.assertIn(
1220 ctx.minimum_version,
1221 {ssl.TLSVersion.TLSv1_2, ssl.TLSVersion.TLSv1_3}
1222 )
1223
1224 with self.assertRaises(ValueError):
1225 ctx.minimum_version = 42
1226
1227 ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_1)
1228
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001229 self.assertIn(
1230 ctx.minimum_version, minimum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001231 )
1232 self.assertEqual(
1233 ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED
1234 )
1235 with self.assertRaises(ValueError):
1236 ctx.minimum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1237 with self.assertRaises(ValueError):
1238 ctx.maximum_version = ssl.TLSVersion.TLSv1
1239
1240
matthewhughes9348e836bb2020-07-17 09:59:15 +01001241 @unittest.skipUnless(
1242 hasattr(ssl.SSLContext, 'security_level'),
1243 "requires OpenSSL >= 1.1.0"
1244 )
1245 def test_security_level(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001246 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
matthewhughes9348e836bb2020-07-17 09:59:15 +01001247 # The default security callback allows for levels between 0-5
1248 # with OpenSSL defaulting to 1, however some vendors override the
1249 # default value (e.g. Debian defaults to 2)
1250 security_level_range = {
1251 0,
1252 1, # OpenSSL default
1253 2, # Debian
1254 3,
1255 4,
1256 5,
1257 }
1258 self.assertIn(ctx.security_level, security_level_range)
1259
Christian Heimes22587792013-11-21 23:56:13 +01001260 def test_verify_flags(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001261 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Benjamin Peterson990fcaa2015-03-04 22:49:41 -05001262 # default value
1263 tf = getattr(ssl, "VERIFY_X509_TRUSTED_FIRST", 0)
1264 self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT | tf)
Christian Heimes22587792013-11-21 23:56:13 +01001265 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF
1266 self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_LEAF)
1267 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_CHAIN
1268 self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_CHAIN)
1269 ctx.verify_flags = ssl.VERIFY_DEFAULT
1270 self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT)
Chris Burre0b4aa02021-03-18 09:24:01 +01001271 ctx.verify_flags = ssl.VERIFY_ALLOW_PROXY_CERTS
1272 self.assertEqual(ctx.verify_flags, ssl.VERIFY_ALLOW_PROXY_CERTS)
Christian Heimes22587792013-11-21 23:56:13 +01001273 # supports any value
1274 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT
1275 self.assertEqual(ctx.verify_flags,
1276 ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT)
1277 with self.assertRaises(TypeError):
1278 ctx.verify_flags = None
1279
Antoine Pitrou152efa22010-05-16 18:19:27 +00001280 def test_load_cert_chain(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001281 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001282 # Combined key and cert in a single file
Benjamin Peterson1ea070e2014-11-03 21:05:01 -05001283 ctx.load_cert_chain(CERTFILE, keyfile=None)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001284 ctx.load_cert_chain(CERTFILE, keyfile=CERTFILE)
1285 self.assertRaises(TypeError, ctx.load_cert_chain, keyfile=CERTFILE)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001286 with self.assertRaises(OSError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001287 ctx.load_cert_chain(NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +00001288 self.assertEqual(cm.exception.errno, errno.ENOENT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001289 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001290 ctx.load_cert_chain(BADCERT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001291 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001292 ctx.load_cert_chain(EMPTYCERT)
1293 # Separate key and cert
Christian Heimesa170fa12017-09-15 20:27:30 +02001294 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001295 ctx.load_cert_chain(ONLYCERT, ONLYKEY)
1296 ctx.load_cert_chain(certfile=ONLYCERT, keyfile=ONLYKEY)
1297 ctx.load_cert_chain(certfile=BYTES_ONLYCERT, keyfile=BYTES_ONLYKEY)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001298 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001299 ctx.load_cert_chain(ONLYCERT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001300 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001301 ctx.load_cert_chain(ONLYKEY)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001302 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001303 ctx.load_cert_chain(certfile=ONLYKEY, keyfile=ONLYCERT)
1304 # Mismatching key and cert
Christian Heimesa170fa12017-09-15 20:27:30 +02001305 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001306 with self.assertRaisesRegex(ssl.SSLError, "key values mismatch"):
Martin Panter3d81d932016-01-14 09:36:00 +00001307 ctx.load_cert_chain(CAFILE_CACERT, ONLYKEY)
Antoine Pitrou4fd1e6a2011-08-25 14:39:44 +02001308 # Password protected key and cert
1309 ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD)
1310 ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD.encode())
1311 ctx.load_cert_chain(CERTFILE_PROTECTED,
1312 password=bytearray(KEY_PASSWORD.encode()))
1313 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD)
1314 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD.encode())
1315 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED,
1316 bytearray(KEY_PASSWORD.encode()))
1317 with self.assertRaisesRegex(TypeError, "should be a string"):
1318 ctx.load_cert_chain(CERTFILE_PROTECTED, password=True)
1319 with self.assertRaises(ssl.SSLError):
1320 ctx.load_cert_chain(CERTFILE_PROTECTED, password="badpass")
1321 with self.assertRaisesRegex(ValueError, "cannot be longer"):
1322 # openssl has a fixed limit on the password buffer.
1323 # PEM_BUFSIZE is generally set to 1kb.
1324 # Return a string larger than this.
1325 ctx.load_cert_chain(CERTFILE_PROTECTED, password=b'a' * 102400)
1326 # Password callback
1327 def getpass_unicode():
1328 return KEY_PASSWORD
1329 def getpass_bytes():
1330 return KEY_PASSWORD.encode()
1331 def getpass_bytearray():
1332 return bytearray(KEY_PASSWORD.encode())
1333 def getpass_badpass():
1334 return "badpass"
1335 def getpass_huge():
1336 return b'a' * (1024 * 1024)
1337 def getpass_bad_type():
1338 return 9
1339 def getpass_exception():
1340 raise Exception('getpass error')
1341 class GetPassCallable:
1342 def __call__(self):
1343 return KEY_PASSWORD
1344 def getpass(self):
1345 return KEY_PASSWORD
1346 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_unicode)
1347 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytes)
1348 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytearray)
1349 ctx.load_cert_chain(CERTFILE_PROTECTED, password=GetPassCallable())
1350 ctx.load_cert_chain(CERTFILE_PROTECTED,
1351 password=GetPassCallable().getpass)
1352 with self.assertRaises(ssl.SSLError):
1353 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_badpass)
1354 with self.assertRaisesRegex(ValueError, "cannot be longer"):
1355 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_huge)
1356 with self.assertRaisesRegex(TypeError, "must return a string"):
1357 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bad_type)
1358 with self.assertRaisesRegex(Exception, "getpass error"):
1359 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_exception)
1360 # Make sure the password function isn't called if it isn't needed
1361 ctx.load_cert_chain(CERTFILE, password=getpass_exception)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001362
1363 def test_load_verify_locations(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001364 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001365 ctx.load_verify_locations(CERTFILE)
1366 ctx.load_verify_locations(cafile=CERTFILE, capath=None)
1367 ctx.load_verify_locations(BYTES_CERTFILE)
1368 ctx.load_verify_locations(cafile=BYTES_CERTFILE, capath=None)
1369 self.assertRaises(TypeError, ctx.load_verify_locations)
Christian Heimesefff7062013-11-21 03:35:02 +01001370 self.assertRaises(TypeError, ctx.load_verify_locations, None, None, None)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001371 with self.assertRaises(OSError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001372 ctx.load_verify_locations(NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +00001373 self.assertEqual(cm.exception.errno, errno.ENOENT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001374 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001375 ctx.load_verify_locations(BADCERT)
1376 ctx.load_verify_locations(CERTFILE, CAPATH)
1377 ctx.load_verify_locations(CERTFILE, capath=BYTES_CAPATH)
1378
Victor Stinner80f75e62011-01-29 11:31:20 +00001379 # Issue #10989: crash if the second argument type is invalid
1380 self.assertRaises(TypeError, ctx.load_verify_locations, None, True)
1381
Christian Heimesefff7062013-11-21 03:35:02 +01001382 def test_load_verify_cadata(self):
1383 # test cadata
1384 with open(CAFILE_CACERT) as f:
1385 cacert_pem = f.read()
1386 cacert_der = ssl.PEM_cert_to_DER_cert(cacert_pem)
1387 with open(CAFILE_NEURONIO) as f:
1388 neuronio_pem = f.read()
1389 neuronio_der = ssl.PEM_cert_to_DER_cert(neuronio_pem)
1390
1391 # test PEM
Christian Heimesa170fa12017-09-15 20:27:30 +02001392 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001393 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 0)
1394 ctx.load_verify_locations(cadata=cacert_pem)
1395 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 1)
1396 ctx.load_verify_locations(cadata=neuronio_pem)
1397 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1398 # cert already in hash table
1399 ctx.load_verify_locations(cadata=neuronio_pem)
1400 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1401
1402 # combined
Christian Heimesa170fa12017-09-15 20:27:30 +02001403 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001404 combined = "\n".join((cacert_pem, neuronio_pem))
1405 ctx.load_verify_locations(cadata=combined)
1406 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1407
1408 # with junk around the certs
Christian Heimesa170fa12017-09-15 20:27:30 +02001409 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001410 combined = ["head", cacert_pem, "other", neuronio_pem, "again",
1411 neuronio_pem, "tail"]
1412 ctx.load_verify_locations(cadata="\n".join(combined))
1413 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1414
1415 # test DER
Christian Heimesa170fa12017-09-15 20:27:30 +02001416 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001417 ctx.load_verify_locations(cadata=cacert_der)
1418 ctx.load_verify_locations(cadata=neuronio_der)
1419 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1420 # cert already in hash table
1421 ctx.load_verify_locations(cadata=cacert_der)
1422 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1423
1424 # combined
Christian Heimesa170fa12017-09-15 20:27:30 +02001425 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001426 combined = b"".join((cacert_der, neuronio_der))
1427 ctx.load_verify_locations(cadata=combined)
1428 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1429
1430 # error cases
Christian Heimesa170fa12017-09-15 20:27:30 +02001431 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001432 self.assertRaises(TypeError, ctx.load_verify_locations, cadata=object)
1433
1434 with self.assertRaisesRegex(ssl.SSLError, "no start line"):
1435 ctx.load_verify_locations(cadata="broken")
1436 with self.assertRaisesRegex(ssl.SSLError, "not enough data"):
1437 ctx.load_verify_locations(cadata=b"broken")
1438
1439
Paul Monsonf3550692019-06-19 13:09:54 -07001440 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001441 def test_load_dh_params(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001442 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001443 ctx.load_dh_params(DHFILE)
1444 if os.name != 'nt':
1445 ctx.load_dh_params(BYTES_DHFILE)
1446 self.assertRaises(TypeError, ctx.load_dh_params)
1447 self.assertRaises(TypeError, ctx.load_dh_params, None)
1448 with self.assertRaises(FileNotFoundError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001449 ctx.load_dh_params(NONEXISTINGCERT)
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001450 self.assertEqual(cm.exception.errno, errno.ENOENT)
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001451 with self.assertRaises(ssl.SSLError) as cm:
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001452 ctx.load_dh_params(CERTFILE)
1453
Antoine Pitroub0182c82010-10-12 20:09:02 +00001454 def test_session_stats(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001455 for proto in {ssl.PROTOCOL_TLS_CLIENT, ssl.PROTOCOL_TLS_SERVER}:
Antoine Pitroub0182c82010-10-12 20:09:02 +00001456 ctx = ssl.SSLContext(proto)
1457 self.assertEqual(ctx.session_stats(), {
1458 'number': 0,
1459 'connect': 0,
1460 'connect_good': 0,
1461 'connect_renegotiate': 0,
1462 'accept': 0,
1463 'accept_good': 0,
1464 'accept_renegotiate': 0,
1465 'hits': 0,
1466 'misses': 0,
1467 'timeouts': 0,
1468 'cache_full': 0,
1469 })
1470
Antoine Pitrou664c2d12010-11-17 20:29:42 +00001471 def test_set_default_verify_paths(self):
1472 # There's not much we can do to test that it acts as expected,
1473 # so just check it doesn't crash or raise an exception.
Christian Heimesa170fa12017-09-15 20:27:30 +02001474 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou664c2d12010-11-17 20:29:42 +00001475 ctx.set_default_verify_paths()
1476
Antoine Pitrou501da612011-12-21 09:27:41 +01001477 @unittest.skipUnless(ssl.HAS_ECDH, "ECDH disabled on this OpenSSL build")
Antoine Pitrou923df6f2011-12-19 17:16:51 +01001478 def test_set_ecdh_curve(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001479 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou923df6f2011-12-19 17:16:51 +01001480 ctx.set_ecdh_curve("prime256v1")
1481 ctx.set_ecdh_curve(b"prime256v1")
1482 self.assertRaises(TypeError, ctx.set_ecdh_curve)
1483 self.assertRaises(TypeError, ctx.set_ecdh_curve, None)
1484 self.assertRaises(ValueError, ctx.set_ecdh_curve, "foo")
1485 self.assertRaises(ValueError, ctx.set_ecdh_curve, b"foo")
1486
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001487 def test_sni_callback(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001488 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001489
1490 # set_servername_callback expects a callable, or None
1491 self.assertRaises(TypeError, ctx.set_servername_callback)
1492 self.assertRaises(TypeError, ctx.set_servername_callback, 4)
1493 self.assertRaises(TypeError, ctx.set_servername_callback, "")
1494 self.assertRaises(TypeError, ctx.set_servername_callback, ctx)
1495
1496 def dummycallback(sock, servername, ctx):
1497 pass
1498 ctx.set_servername_callback(None)
1499 ctx.set_servername_callback(dummycallback)
1500
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001501 def test_sni_callback_refcycle(self):
1502 # Reference cycles through the servername callback are detected
1503 # and cleared.
Christian Heimesa170fa12017-09-15 20:27:30 +02001504 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001505 def dummycallback(sock, servername, ctx, cycle=ctx):
1506 pass
1507 ctx.set_servername_callback(dummycallback)
1508 wr = weakref.ref(ctx)
1509 del ctx, dummycallback
1510 gc.collect()
1511 self.assertIs(wr(), None)
1512
Christian Heimes9a5395a2013-06-17 15:44:12 +02001513 def test_cert_store_stats(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001514 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001515 self.assertEqual(ctx.cert_store_stats(),
1516 {'x509_ca': 0, 'crl': 0, 'x509': 0})
1517 ctx.load_cert_chain(CERTFILE)
1518 self.assertEqual(ctx.cert_store_stats(),
1519 {'x509_ca': 0, 'crl': 0, 'x509': 0})
1520 ctx.load_verify_locations(CERTFILE)
1521 self.assertEqual(ctx.cert_store_stats(),
1522 {'x509_ca': 0, 'crl': 0, 'x509': 1})
Martin Panterb55f8b72016-01-14 12:53:56 +00001523 ctx.load_verify_locations(CAFILE_CACERT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001524 self.assertEqual(ctx.cert_store_stats(),
1525 {'x509_ca': 1, 'crl': 0, 'x509': 2})
1526
1527 def test_get_ca_certs(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001528 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001529 self.assertEqual(ctx.get_ca_certs(), [])
1530 # CERTFILE is not flagged as X509v3 Basic Constraints: CA:TRUE
1531 ctx.load_verify_locations(CERTFILE)
1532 self.assertEqual(ctx.get_ca_certs(), [])
Martin Panterb55f8b72016-01-14 12:53:56 +00001533 # but CAFILE_CACERT is a CA cert
1534 ctx.load_verify_locations(CAFILE_CACERT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001535 self.assertEqual(ctx.get_ca_certs(),
1536 [{'issuer': ((('organizationName', 'Root CA'),),
1537 (('organizationalUnitName', 'http://www.cacert.org'),),
1538 (('commonName', 'CA Cert Signing Authority'),),
1539 (('emailAddress', 'support@cacert.org'),)),
Christian Heimesd37b74f2021-04-19 08:31:29 +02001540 'notAfter': 'Mar 29 12:29:49 2033 GMT',
1541 'notBefore': 'Mar 30 12:29:49 2003 GMT',
Christian Heimes9a5395a2013-06-17 15:44:12 +02001542 'serialNumber': '00',
Christian Heimesbd3a7f92013-11-21 03:40:15 +01001543 'crlDistributionPoints': ('https://www.cacert.org/revoke.crl',),
Christian Heimes9a5395a2013-06-17 15:44:12 +02001544 'subject': ((('organizationName', 'Root CA'),),
1545 (('organizationalUnitName', 'http://www.cacert.org'),),
1546 (('commonName', 'CA Cert Signing Authority'),),
1547 (('emailAddress', 'support@cacert.org'),)),
1548 'version': 3}])
1549
Martin Panterb55f8b72016-01-14 12:53:56 +00001550 with open(CAFILE_CACERT) as f:
Christian Heimes9a5395a2013-06-17 15:44:12 +02001551 pem = f.read()
1552 der = ssl.PEM_cert_to_DER_cert(pem)
1553 self.assertEqual(ctx.get_ca_certs(True), [der])
1554
Christian Heimes72d28502013-11-23 13:56:58 +01001555 def test_load_default_certs(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001556 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001557 ctx.load_default_certs()
1558
Christian Heimesa170fa12017-09-15 20:27:30 +02001559 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001560 ctx.load_default_certs(ssl.Purpose.SERVER_AUTH)
1561 ctx.load_default_certs()
1562
Christian Heimesa170fa12017-09-15 20:27:30 +02001563 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001564 ctx.load_default_certs(ssl.Purpose.CLIENT_AUTH)
1565
Christian Heimesa170fa12017-09-15 20:27:30 +02001566 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001567 self.assertRaises(TypeError, ctx.load_default_certs, None)
1568 self.assertRaises(TypeError, ctx.load_default_certs, 'SERVER_AUTH')
1569
Benjamin Peterson91244e02014-10-03 18:17:15 -04001570 @unittest.skipIf(sys.platform == "win32", "not-Windows specific")
Benjamin Peterson5915b0f2014-10-03 17:27:05 -04001571 def test_load_default_certs_env(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001572 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Hai Shia7f5d932020-08-04 00:41:24 +08001573 with os_helper.EnvironmentVarGuard() as env:
Benjamin Peterson5915b0f2014-10-03 17:27:05 -04001574 env["SSL_CERT_DIR"] = CAPATH
1575 env["SSL_CERT_FILE"] = CERTFILE
1576 ctx.load_default_certs()
1577 self.assertEqual(ctx.cert_store_stats(), {"crl": 0, "x509": 1, "x509_ca": 0})
1578
Benjamin Peterson91244e02014-10-03 18:17:15 -04001579 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
Steve Dower68d663c2017-07-17 11:15:48 +02001580 @unittest.skipIf(hasattr(sys, "gettotalrefcount"), "Debug build does not share environment between CRTs")
Benjamin Peterson91244e02014-10-03 18:17:15 -04001581 def test_load_default_certs_env_windows(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001582 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Benjamin Peterson91244e02014-10-03 18:17:15 -04001583 ctx.load_default_certs()
1584 stats = ctx.cert_store_stats()
1585
Christian Heimesa170fa12017-09-15 20:27:30 +02001586 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Hai Shia7f5d932020-08-04 00:41:24 +08001587 with os_helper.EnvironmentVarGuard() as env:
Benjamin Peterson91244e02014-10-03 18:17:15 -04001588 env["SSL_CERT_DIR"] = CAPATH
1589 env["SSL_CERT_FILE"] = CERTFILE
1590 ctx.load_default_certs()
1591 stats["x509"] += 1
1592 self.assertEqual(ctx.cert_store_stats(), stats)
1593
Christian Heimes358cfd42016-09-10 22:43:48 +02001594 def _assert_context_options(self, ctx):
1595 self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
1596 if OP_NO_COMPRESSION != 0:
1597 self.assertEqual(ctx.options & OP_NO_COMPRESSION,
1598 OP_NO_COMPRESSION)
1599 if OP_SINGLE_DH_USE != 0:
1600 self.assertEqual(ctx.options & OP_SINGLE_DH_USE,
1601 OP_SINGLE_DH_USE)
1602 if OP_SINGLE_ECDH_USE != 0:
1603 self.assertEqual(ctx.options & OP_SINGLE_ECDH_USE,
1604 OP_SINGLE_ECDH_USE)
1605 if OP_CIPHER_SERVER_PREFERENCE != 0:
1606 self.assertEqual(ctx.options & OP_CIPHER_SERVER_PREFERENCE,
1607 OP_CIPHER_SERVER_PREFERENCE)
1608
Christian Heimes4c05b472013-11-23 15:58:30 +01001609 def test_create_default_context(self):
1610 ctx = ssl.create_default_context()
Christian Heimes358cfd42016-09-10 22:43:48 +02001611
Christian Heimes2875c602021-04-19 07:27:10 +02001612 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes4c05b472013-11-23 15:58:30 +01001613 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001614 self.assertTrue(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001615 self._assert_context_options(ctx)
1616
Christian Heimes4c05b472013-11-23 15:58:30 +01001617 with open(SIGNING_CA) as f:
1618 cadata = f.read()
1619 ctx = ssl.create_default_context(cafile=SIGNING_CA, capath=CAPATH,
1620 cadata=cadata)
Christian Heimes2875c602021-04-19 07:27:10 +02001621 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes4c05b472013-11-23 15:58:30 +01001622 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes358cfd42016-09-10 22:43:48 +02001623 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001624
1625 ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
Christian Heimes2875c602021-04-19 07:27:10 +02001626 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_SERVER)
Christian Heimes4c05b472013-11-23 15:58:30 +01001627 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001628 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001629
Christian Heimes2875c602021-04-19 07:27:10 +02001630
1631
Christian Heimes67986f92013-11-23 22:43:47 +01001632 def test__create_stdlib_context(self):
1633 ctx = ssl._create_stdlib_context()
Christian Heimes2875c602021-04-19 07:27:10 +02001634 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes67986f92013-11-23 22:43:47 +01001635 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001636 self.assertFalse(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001637 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001638
Christian Heimes2875c602021-04-19 07:27:10 +02001639 with warnings_helper.check_warnings():
1640 ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1)
Christian Heimes67986f92013-11-23 22:43:47 +01001641 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
1642 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001643 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001644
Christian Heimes2875c602021-04-19 07:27:10 +02001645 with warnings_helper.check_warnings():
1646 ctx = ssl._create_stdlib_context(
1647 ssl.PROTOCOL_TLSv1_2,
1648 cert_reqs=ssl.CERT_REQUIRED,
1649 check_hostname=True
1650 )
1651 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1_2)
Christian Heimes67986f92013-11-23 22:43:47 +01001652 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimesa02c69a2013-12-02 20:59:28 +01001653 self.assertTrue(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001654 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001655
1656 ctx = ssl._create_stdlib_context(purpose=ssl.Purpose.CLIENT_AUTH)
Christian Heimes2875c602021-04-19 07:27:10 +02001657 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_SERVER)
Christian Heimes67986f92013-11-23 22:43:47 +01001658 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001659 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001660
Christian Heimes1aa9a752013-12-02 02:41:19 +01001661 def test_check_hostname(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001662 with warnings_helper.check_warnings():
1663 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001664 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001665 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001666
Christian Heimese82c0342017-09-15 20:29:57 +02001667 # Auto set CERT_REQUIRED
1668 ctx.check_hostname = True
1669 self.assertTrue(ctx.check_hostname)
1670 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1671 ctx.check_hostname = False
Christian Heimes1aa9a752013-12-02 02:41:19 +01001672 ctx.verify_mode = ssl.CERT_REQUIRED
1673 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001674 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001675
Christian Heimese82c0342017-09-15 20:29:57 +02001676 # Changing verify_mode does not affect check_hostname
1677 ctx.check_hostname = False
1678 ctx.verify_mode = ssl.CERT_NONE
1679 ctx.check_hostname = False
1680 self.assertFalse(ctx.check_hostname)
1681 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1682 # Auto set
Christian Heimes1aa9a752013-12-02 02:41:19 +01001683 ctx.check_hostname = True
1684 self.assertTrue(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001685 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1686
1687 ctx.check_hostname = False
1688 ctx.verify_mode = ssl.CERT_OPTIONAL
1689 ctx.check_hostname = False
1690 self.assertFalse(ctx.check_hostname)
1691 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1692 # keep CERT_OPTIONAL
1693 ctx.check_hostname = True
1694 self.assertTrue(ctx.check_hostname)
1695 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001696
1697 # Cannot set CERT_NONE with check_hostname enabled
1698 with self.assertRaises(ValueError):
1699 ctx.verify_mode = ssl.CERT_NONE
1700 ctx.check_hostname = False
1701 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001702 ctx.verify_mode = ssl.CERT_NONE
1703 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001704
Christian Heimes5fe668c2016-09-12 00:01:11 +02001705 def test_context_client_server(self):
1706 # PROTOCOL_TLS_CLIENT has sane defaults
1707 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1708 self.assertTrue(ctx.check_hostname)
1709 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1710
1711 # PROTOCOL_TLS_SERVER has different but also sane defaults
1712 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1713 self.assertFalse(ctx.check_hostname)
1714 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1715
Christian Heimes4df60f12017-09-15 20:26:05 +02001716 def test_context_custom_class(self):
1717 class MySSLSocket(ssl.SSLSocket):
1718 pass
1719
1720 class MySSLObject(ssl.SSLObject):
1721 pass
1722
1723 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1724 ctx.sslsocket_class = MySSLSocket
1725 ctx.sslobject_class = MySSLObject
1726
1727 with ctx.wrap_socket(socket.socket(), server_side=True) as sock:
1728 self.assertIsInstance(sock, MySSLSocket)
1729 obj = ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO())
1730 self.assertIsInstance(obj, MySSLObject)
1731
Christian Heimes78c7d522019-06-03 21:00:10 +02001732 def test_num_tickest(self):
1733 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1734 self.assertEqual(ctx.num_tickets, 2)
1735 ctx.num_tickets = 1
1736 self.assertEqual(ctx.num_tickets, 1)
1737 ctx.num_tickets = 0
1738 self.assertEqual(ctx.num_tickets, 0)
1739 with self.assertRaises(ValueError):
1740 ctx.num_tickets = -1
1741 with self.assertRaises(TypeError):
1742 ctx.num_tickets = None
1743
1744 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1745 self.assertEqual(ctx.num_tickets, 2)
1746 with self.assertRaises(ValueError):
1747 ctx.num_tickets = 1
1748
Antoine Pitrou152efa22010-05-16 18:19:27 +00001749
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001750class SSLErrorTests(unittest.TestCase):
1751
1752 def test_str(self):
1753 # The str() of a SSLError doesn't include the errno
1754 e = ssl.SSLError(1, "foo")
1755 self.assertEqual(str(e), "foo")
1756 self.assertEqual(e.errno, 1)
1757 # Same for a subclass
1758 e = ssl.SSLZeroReturnError(1, "foo")
1759 self.assertEqual(str(e), "foo")
1760 self.assertEqual(e.errno, 1)
1761
Paul Monsonf3550692019-06-19 13:09:54 -07001762 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001763 def test_lib_reason(self):
1764 # Test the library and reason attributes
Christian Heimesa170fa12017-09-15 20:27:30 +02001765 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001766 with self.assertRaises(ssl.SSLError) as cm:
1767 ctx.load_dh_params(CERTFILE)
1768 self.assertEqual(cm.exception.library, 'PEM')
1769 self.assertEqual(cm.exception.reason, 'NO_START_LINE')
1770 s = str(cm.exception)
1771 self.assertTrue(s.startswith("[PEM: NO_START_LINE] no start line"), s)
1772
1773 def test_subclass(self):
1774 # Check that the appropriate SSLError subclass is raised
1775 # (this only tests one of them)
Christian Heimesa170fa12017-09-15 20:27:30 +02001776 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1777 ctx.check_hostname = False
1778 ctx.verify_mode = ssl.CERT_NONE
Giampaolo Rodolaeb7e29f2019-04-09 00:34:02 +02001779 with socket.create_server(("127.0.0.1", 0)) as s:
1780 c = socket.create_connection(s.getsockname())
Antoine Pitroue1ceb502013-01-12 21:54:44 +01001781 c.setblocking(False)
1782 with ctx.wrap_socket(c, False, do_handshake_on_connect=False) as c:
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001783 with self.assertRaises(ssl.SSLWantReadError) as cm:
1784 c.do_handshake()
1785 s = str(cm.exception)
1786 self.assertTrue(s.startswith("The operation did not complete (read)"), s)
1787 # For compatibility
1788 self.assertEqual(cm.exception.errno, ssl.SSL_ERROR_WANT_READ)
1789
1790
Christian Heimes61d478c2018-01-27 15:51:38 +01001791 def test_bad_server_hostname(self):
1792 ctx = ssl.create_default_context()
1793 with self.assertRaises(ValueError):
1794 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1795 server_hostname="")
1796 with self.assertRaises(ValueError):
1797 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1798 server_hostname=".example.org")
Christian Heimesd02ac252018-03-25 12:36:13 +02001799 with self.assertRaises(TypeError):
1800 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1801 server_hostname="example.org\x00evil.com")
Christian Heimes61d478c2018-01-27 15:51:38 +01001802
1803
Antoine Pitroub1fdf472014-10-05 20:41:53 +02001804class MemoryBIOTests(unittest.TestCase):
1805
1806 def test_read_write(self):
1807 bio = ssl.MemoryBIO()
1808 bio.write(b'foo')
1809 self.assertEqual(bio.read(), b'foo')
1810 self.assertEqual(bio.read(), b'')
1811 bio.write(b'foo')
1812 bio.write(b'bar')
1813 self.assertEqual(bio.read(), b'foobar')
1814 self.assertEqual(bio.read(), b'')
1815 bio.write(b'baz')
1816 self.assertEqual(bio.read(2), b'ba')
1817 self.assertEqual(bio.read(1), b'z')
1818 self.assertEqual(bio.read(1), b'')
1819
1820 def test_eof(self):
1821 bio = ssl.MemoryBIO()
1822 self.assertFalse(bio.eof)
1823 self.assertEqual(bio.read(), b'')
1824 self.assertFalse(bio.eof)
1825 bio.write(b'foo')
1826 self.assertFalse(bio.eof)
1827 bio.write_eof()
1828 self.assertFalse(bio.eof)
1829 self.assertEqual(bio.read(2), b'fo')
1830 self.assertFalse(bio.eof)
1831 self.assertEqual(bio.read(1), b'o')
1832 self.assertTrue(bio.eof)
1833 self.assertEqual(bio.read(), b'')
1834 self.assertTrue(bio.eof)
1835
1836 def test_pending(self):
1837 bio = ssl.MemoryBIO()
1838 self.assertEqual(bio.pending, 0)
1839 bio.write(b'foo')
1840 self.assertEqual(bio.pending, 3)
1841 for i in range(3):
1842 bio.read(1)
1843 self.assertEqual(bio.pending, 3-i-1)
1844 for i in range(3):
1845 bio.write(b'x')
1846 self.assertEqual(bio.pending, i+1)
1847 bio.read()
1848 self.assertEqual(bio.pending, 0)
1849
1850 def test_buffer_types(self):
1851 bio = ssl.MemoryBIO()
1852 bio.write(b'foo')
1853 self.assertEqual(bio.read(), b'foo')
1854 bio.write(bytearray(b'bar'))
1855 self.assertEqual(bio.read(), b'bar')
1856 bio.write(memoryview(b'baz'))
1857 self.assertEqual(bio.read(), b'baz')
1858
1859 def test_error_types(self):
1860 bio = ssl.MemoryBIO()
1861 self.assertRaises(TypeError, bio.write, 'foo')
1862 self.assertRaises(TypeError, bio.write, None)
1863 self.assertRaises(TypeError, bio.write, True)
1864 self.assertRaises(TypeError, bio.write, 1)
1865
1866
Christian Heimes9d50ab52018-02-27 10:17:30 +01001867class SSLObjectTests(unittest.TestCase):
1868 def test_private_init(self):
1869 bio = ssl.MemoryBIO()
1870 with self.assertRaisesRegex(TypeError, "public constructor"):
1871 ssl.SSLObject(bio, bio)
1872
Nathaniel J. Smithc0da5822018-09-21 21:44:12 -07001873 def test_unwrap(self):
1874 client_ctx, server_ctx, hostname = testing_context()
1875 c_in = ssl.MemoryBIO()
1876 c_out = ssl.MemoryBIO()
1877 s_in = ssl.MemoryBIO()
1878 s_out = ssl.MemoryBIO()
1879 client = client_ctx.wrap_bio(c_in, c_out, server_hostname=hostname)
1880 server = server_ctx.wrap_bio(s_in, s_out, server_side=True)
1881
1882 # Loop on the handshake for a bit to get it settled
1883 for _ in range(5):
1884 try:
1885 client.do_handshake()
1886 except ssl.SSLWantReadError:
1887 pass
1888 if c_out.pending:
1889 s_in.write(c_out.read())
1890 try:
1891 server.do_handshake()
1892 except ssl.SSLWantReadError:
1893 pass
1894 if s_out.pending:
1895 c_in.write(s_out.read())
1896 # Now the handshakes should be complete (don't raise WantReadError)
1897 client.do_handshake()
1898 server.do_handshake()
1899
1900 # Now if we unwrap one side unilaterally, it should send close-notify
1901 # and raise WantReadError:
1902 with self.assertRaises(ssl.SSLWantReadError):
1903 client.unwrap()
1904
1905 # But server.unwrap() does not raise, because it reads the client's
1906 # close-notify:
1907 s_in.write(c_out.read())
1908 server.unwrap()
1909
1910 # And now that the client gets the server's close-notify, it doesn't
1911 # raise either.
1912 c_in.write(s_out.read())
1913 client.unwrap()
Christian Heimes9d50ab52018-02-27 10:17:30 +01001914
Martin Panter3840b2a2016-03-27 01:53:46 +00001915class SimpleBackgroundTests(unittest.TestCase):
Martin Panter3840b2a2016-03-27 01:53:46 +00001916 """Tests that connect to a simple server running in the background"""
1917
1918 def setUp(self):
juhovh49fdf112021-04-18 21:11:48 +10001919 self.server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1920 self.server_context.load_cert_chain(SIGNED_CERTFILE)
1921 server = ThreadedEchoServer(context=self.server_context)
Martin Panter3840b2a2016-03-27 01:53:46 +00001922 self.server_addr = (HOST, server.port)
1923 server.__enter__()
1924 self.addCleanup(server.__exit__, None, None, None)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001925
Antoine Pitrou480a1242010-04-28 21:37:09 +00001926 def test_connect(self):
Christian Heimesd0486372016-09-10 23:23:33 +02001927 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001928 cert_reqs=ssl.CERT_NONE) as s:
1929 s.connect(self.server_addr)
1930 self.assertEqual({}, s.getpeercert())
Christian Heimesa5d07652016-09-24 10:48:05 +02001931 self.assertFalse(s.server_side)
Antoine Pitrou350c7222010-09-09 13:31:46 +00001932
Martin Panter3840b2a2016-03-27 01:53:46 +00001933 # this should succeed because we specify the root cert
Christian Heimesd0486372016-09-10 23:23:33 +02001934 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001935 cert_reqs=ssl.CERT_REQUIRED,
1936 ca_certs=SIGNING_CA) as s:
1937 s.connect(self.server_addr)
1938 self.assertTrue(s.getpeercert())
Christian Heimesa5d07652016-09-24 10:48:05 +02001939 self.assertFalse(s.server_side)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001940
Martin Panter3840b2a2016-03-27 01:53:46 +00001941 def test_connect_fail(self):
1942 # This should fail because we have no verification certs. Connection
1943 # failure crashes ThreadedEchoServer, so run this in an independent
1944 # test method.
Christian Heimesd0486372016-09-10 23:23:33 +02001945 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001946 cert_reqs=ssl.CERT_REQUIRED)
1947 self.addCleanup(s.close)
1948 self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
1949 s.connect, self.server_addr)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001950
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00001951 def test_connect_ex(self):
1952 # Issue #11326: check connect_ex() implementation
Christian Heimesd0486372016-09-10 23:23:33 +02001953 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001954 cert_reqs=ssl.CERT_REQUIRED,
1955 ca_certs=SIGNING_CA)
1956 self.addCleanup(s.close)
1957 self.assertEqual(0, s.connect_ex(self.server_addr))
1958 self.assertTrue(s.getpeercert())
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00001959
1960 def test_non_blocking_connect_ex(self):
1961 # Issue #11326: non-blocking connect_ex() should allow handshake
1962 # to proceed after the socket gets ready.
Christian Heimesd0486372016-09-10 23:23:33 +02001963 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001964 cert_reqs=ssl.CERT_REQUIRED,
1965 ca_certs=SIGNING_CA,
1966 do_handshake_on_connect=False)
1967 self.addCleanup(s.close)
1968 s.setblocking(False)
1969 rc = s.connect_ex(self.server_addr)
1970 # EWOULDBLOCK under Windows, EINPROGRESS elsewhere
1971 self.assertIn(rc, (0, errno.EINPROGRESS, errno.EWOULDBLOCK))
1972 # Wait for connect to finish
1973 select.select([], [s], [], 5.0)
1974 # Non-blocking handshake
1975 while True:
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00001976 try:
Martin Panter3840b2a2016-03-27 01:53:46 +00001977 s.do_handshake()
1978 break
1979 except ssl.SSLWantReadError:
1980 select.select([s], [], [], 5.0)
1981 except ssl.SSLWantWriteError:
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00001982 select.select([], [s], [], 5.0)
Martin Panter3840b2a2016-03-27 01:53:46 +00001983 # SSL established
1984 self.assertTrue(s.getpeercert())
Antoine Pitrou40f12ab2012-12-28 19:03:43 +01001985
Antoine Pitrou152efa22010-05-16 18:19:27 +00001986 def test_connect_with_context(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00001987 # Same as test_connect, but with a separately created context
Christian Heimes2875c602021-04-19 07:27:10 +02001988 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1989 ctx.check_hostname = False
1990 ctx.verify_mode = ssl.CERT_NONE
Martin Panter3840b2a2016-03-27 01:53:46 +00001991 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
1992 s.connect(self.server_addr)
1993 self.assertEqual({}, s.getpeercert())
1994 # Same with a server hostname
1995 with ctx.wrap_socket(socket.socket(socket.AF_INET),
1996 server_hostname="dummy") as s:
1997 s.connect(self.server_addr)
1998 ctx.verify_mode = ssl.CERT_REQUIRED
1999 # This should succeed because we specify the root cert
2000 ctx.load_verify_locations(SIGNING_CA)
2001 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2002 s.connect(self.server_addr)
2003 cert = s.getpeercert()
2004 self.assertTrue(cert)
2005
2006 def test_connect_with_context_fail(self):
2007 # This should fail because we have no verification certs. Connection
2008 # failure crashes ThreadedEchoServer, so run this in an independent
2009 # test method.
Christian Heimes2875c602021-04-19 07:27:10 +02002010 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2011 s = ctx.wrap_socket(
2012 socket.socket(socket.AF_INET),
2013 server_hostname=SIGNED_CERTFILE_HOSTNAME
2014 )
Martin Panter3840b2a2016-03-27 01:53:46 +00002015 self.addCleanup(s.close)
2016 self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
2017 s.connect, self.server_addr)
Antoine Pitrou152efa22010-05-16 18:19:27 +00002018
2019 def test_connect_capath(self):
2020 # Verify server certificates using the `capath` argument
Antoine Pitrou467f28d2010-05-16 19:22:44 +00002021 # NOTE: the subject hashing algorithm has been changed between
2022 # OpenSSL 0.9.8n and 1.0.0, as a result the capath directory must
2023 # contain both versions of each certificate (same content, different
Antoine Pitroud7e4c1c2010-05-17 14:13:10 +00002024 # filename) for this test to be portable across OpenSSL releases.
Christian Heimes2875c602021-04-19 07:27:10 +02002025 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002026 ctx.load_verify_locations(capath=CAPATH)
Christian Heimes2875c602021-04-19 07:27:10 +02002027 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2028 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002029 s.connect(self.server_addr)
2030 cert = s.getpeercert()
2031 self.assertTrue(cert)
Christian Heimes529525f2018-05-23 22:24:45 +02002032
Martin Panter3840b2a2016-03-27 01:53:46 +00002033 # Same with a bytes `capath` argument
Christian Heimes2875c602021-04-19 07:27:10 +02002034 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002035 ctx.load_verify_locations(capath=BYTES_CAPATH)
Christian Heimes2875c602021-04-19 07:27:10 +02002036 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2037 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002038 s.connect(self.server_addr)
2039 cert = s.getpeercert()
2040 self.assertTrue(cert)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002041
Christian Heimesefff7062013-11-21 03:35:02 +01002042 def test_connect_cadata(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002043 with open(SIGNING_CA) as f:
Christian Heimesefff7062013-11-21 03:35:02 +01002044 pem = f.read()
2045 der = ssl.PEM_cert_to_DER_cert(pem)
Christian Heimes2875c602021-04-19 07:27:10 +02002046 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002047 ctx.load_verify_locations(cadata=pem)
Christian Heimes2875c602021-04-19 07:27:10 +02002048 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2049 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002050 s.connect(self.server_addr)
2051 cert = s.getpeercert()
2052 self.assertTrue(cert)
Christian Heimesefff7062013-11-21 03:35:02 +01002053
Martin Panter3840b2a2016-03-27 01:53:46 +00002054 # same with DER
Christian Heimes2875c602021-04-19 07:27:10 +02002055 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002056 ctx.load_verify_locations(cadata=der)
Christian Heimes2875c602021-04-19 07:27:10 +02002057 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2058 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002059 s.connect(self.server_addr)
2060 cert = s.getpeercert()
2061 self.assertTrue(cert)
Christian Heimesefff7062013-11-21 03:35:02 +01002062
Antoine Pitroue3220242010-04-24 11:13:53 +00002063 @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
2064 def test_makefile_close(self):
2065 # Issue #5238: creating a file-like object with makefile() shouldn't
2066 # delay closing the underlying "real socket" (here tested with its
2067 # file descriptor, hence skipping the test under Windows).
Christian Heimesd0486372016-09-10 23:23:33 +02002068 ss = test_wrap_socket(socket.socket(socket.AF_INET))
Martin Panter3840b2a2016-03-27 01:53:46 +00002069 ss.connect(self.server_addr)
2070 fd = ss.fileno()
2071 f = ss.makefile()
2072 f.close()
2073 # The fd is still open
2074 os.read(fd, 0)
2075 # Closing the SSL socket should close the fd too
2076 ss.close()
2077 gc.collect()
2078 with self.assertRaises(OSError) as e:
Antoine Pitroue3220242010-04-24 11:13:53 +00002079 os.read(fd, 0)
Martin Panter3840b2a2016-03-27 01:53:46 +00002080 self.assertEqual(e.exception.errno, errno.EBADF)
Antoine Pitroue3220242010-04-24 11:13:53 +00002081
Antoine Pitrou480a1242010-04-28 21:37:09 +00002082 def test_non_blocking_handshake(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002083 s = socket.socket(socket.AF_INET)
2084 s.connect(self.server_addr)
2085 s.setblocking(False)
Christian Heimesd0486372016-09-10 23:23:33 +02002086 s = test_wrap_socket(s,
Martin Panter3840b2a2016-03-27 01:53:46 +00002087 cert_reqs=ssl.CERT_NONE,
2088 do_handshake_on_connect=False)
2089 self.addCleanup(s.close)
2090 count = 0
2091 while True:
2092 try:
2093 count += 1
2094 s.do_handshake()
2095 break
2096 except ssl.SSLWantReadError:
2097 select.select([s], [], [])
2098 except ssl.SSLWantWriteError:
2099 select.select([], [s], [])
2100 if support.verbose:
2101 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002102
Antoine Pitrou480a1242010-04-28 21:37:09 +00002103 def test_get_server_certificate(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002104 _test_get_server_certificate(self, *self.server_addr, cert=SIGNING_CA)
Antoine Pitrou5aefa662011-04-28 19:24:46 +02002105
juhovh49fdf112021-04-18 21:11:48 +10002106 def test_get_server_certificate_sni(self):
2107 host, port = self.server_addr
2108 server_names = []
2109
2110 # We store servername_cb arguments to make sure they match the host
2111 def servername_cb(ssl_sock, server_name, initial_context):
2112 server_names.append(server_name)
2113 self.server_context.set_servername_callback(servername_cb)
2114
2115 pem = ssl.get_server_certificate((host, port))
2116 if not pem:
2117 self.fail("No server certificate on %s:%s!" % (host, port))
2118
2119 pem = ssl.get_server_certificate((host, port), ca_certs=SIGNING_CA)
2120 if not pem:
2121 self.fail("No server certificate on %s:%s!" % (host, port))
2122 if support.verbose:
2123 sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port, pem))
2124
2125 self.assertEqual(server_names, [host, host])
2126
Martin Panter3840b2a2016-03-27 01:53:46 +00002127 def test_get_server_certificate_fail(self):
2128 # Connection failure crashes ThreadedEchoServer, so run this in an
2129 # independent test method
2130 _test_get_server_certificate_fail(self, *self.server_addr)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002131
Antoine Pitrouf4c7bad2010-08-15 23:02:22 +00002132 def test_ciphers(self):
Christian Heimesd0486372016-09-10 23:23:33 +02002133 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002134 cert_reqs=ssl.CERT_NONE, ciphers="ALL") as s:
2135 s.connect(self.server_addr)
Christian Heimesd0486372016-09-10 23:23:33 +02002136 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002137 cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT") as s:
2138 s.connect(self.server_addr)
2139 # Error checking can happen at instantiation or when connecting
2140 with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
2141 with socket.socket(socket.AF_INET) as sock:
Christian Heimesd0486372016-09-10 23:23:33 +02002142 s = test_wrap_socket(sock,
Martin Panter3840b2a2016-03-27 01:53:46 +00002143 cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
2144 s.connect(self.server_addr)
Antoine Pitroufec12ff2010-04-21 19:46:23 +00002145
Christian Heimes9a5395a2013-06-17 15:44:12 +02002146 def test_get_ca_certs_capath(self):
2147 # capath certs are loaded on request
Christian Heimesa170fa12017-09-15 20:27:30 +02002148 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002149 ctx.load_verify_locations(capath=CAPATH)
2150 self.assertEqual(ctx.get_ca_certs(), [])
Christian Heimesa170fa12017-09-15 20:27:30 +02002151 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2152 server_hostname='localhost') as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002153 s.connect(self.server_addr)
2154 cert = s.getpeercert()
2155 self.assertTrue(cert)
2156 self.assertEqual(len(ctx.get_ca_certs()), 1)
Christian Heimes9a5395a2013-06-17 15:44:12 +02002157
Christian Heimes8e7f3942013-12-05 07:41:08 +01002158 def test_context_setget(self):
2159 # Check that the context of a connected socket can be replaced.
Christian Heimesa170fa12017-09-15 20:27:30 +02002160 ctx1 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2161 ctx1.load_verify_locations(capath=CAPATH)
2162 ctx2 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2163 ctx2.load_verify_locations(capath=CAPATH)
Martin Panter3840b2a2016-03-27 01:53:46 +00002164 s = socket.socket(socket.AF_INET)
Christian Heimesa170fa12017-09-15 20:27:30 +02002165 with ctx1.wrap_socket(s, server_hostname='localhost') as ss:
Martin Panter3840b2a2016-03-27 01:53:46 +00002166 ss.connect(self.server_addr)
2167 self.assertIs(ss.context, ctx1)
2168 self.assertIs(ss._sslobj.context, ctx1)
2169 ss.context = ctx2
2170 self.assertIs(ss.context, ctx2)
2171 self.assertIs(ss._sslobj.context, ctx2)
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002172
2173 def ssl_io_loop(self, sock, incoming, outgoing, func, *args, **kwargs):
2174 # A simple IO loop. Call func(*args) depending on the error we get
2175 # (WANT_READ or WANT_WRITE) move data between the socket and the BIOs.
Victor Stinner0d63bac2019-12-11 11:30:03 +01002176 timeout = kwargs.get('timeout', support.SHORT_TIMEOUT)
Victor Stinner50a72af2017-09-11 09:34:24 -07002177 deadline = time.monotonic() + timeout
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002178 count = 0
2179 while True:
Victor Stinner50a72af2017-09-11 09:34:24 -07002180 if time.monotonic() > deadline:
2181 self.fail("timeout")
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002182 errno = None
2183 count += 1
2184 try:
2185 ret = func(*args)
2186 except ssl.SSLError as e:
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002187 if e.errno not in (ssl.SSL_ERROR_WANT_READ,
Martin Panter40b97ec2016-01-14 13:05:46 +00002188 ssl.SSL_ERROR_WANT_WRITE):
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002189 raise
2190 errno = e.errno
2191 # Get any data from the outgoing BIO irrespective of any error, and
2192 # send it to the socket.
2193 buf = outgoing.read()
2194 sock.sendall(buf)
2195 # If there's no error, we're done. For WANT_READ, we need to get
2196 # data from the socket and put it in the incoming BIO.
2197 if errno is None:
2198 break
2199 elif errno == ssl.SSL_ERROR_WANT_READ:
2200 buf = sock.recv(32768)
2201 if buf:
2202 incoming.write(buf)
2203 else:
2204 incoming.write_eof()
2205 if support.verbose:
2206 sys.stdout.write("Needed %d calls to complete %s().\n"
2207 % (count, func.__name__))
2208 return ret
2209
Martin Panter3840b2a2016-03-27 01:53:46 +00002210 def test_bio_handshake(self):
2211 sock = socket.socket(socket.AF_INET)
2212 self.addCleanup(sock.close)
2213 sock.connect(self.server_addr)
2214 incoming = ssl.MemoryBIO()
2215 outgoing = ssl.MemoryBIO()
Christian Heimesa170fa12017-09-15 20:27:30 +02002216 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2217 self.assertTrue(ctx.check_hostname)
2218 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Martin Panter3840b2a2016-03-27 01:53:46 +00002219 ctx.load_verify_locations(SIGNING_CA)
Christian Heimesa170fa12017-09-15 20:27:30 +02002220 sslobj = ctx.wrap_bio(incoming, outgoing, False,
2221 SIGNED_CERTFILE_HOSTNAME)
Martin Panter3840b2a2016-03-27 01:53:46 +00002222 self.assertIs(sslobj._sslobj.owner, sslobj)
2223 self.assertIsNone(sslobj.cipher())
Christian Heimes68771112017-09-05 21:55:40 -07002224 self.assertIsNone(sslobj.version())
Christian Heimes01113fa2016-09-05 23:23:24 +02002225 self.assertIsNotNone(sslobj.shared_ciphers())
Martin Panter3840b2a2016-03-27 01:53:46 +00002226 self.assertRaises(ValueError, sslobj.getpeercert)
2227 if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
2228 self.assertIsNone(sslobj.get_channel_binding('tls-unique'))
2229 self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
2230 self.assertTrue(sslobj.cipher())
Christian Heimes01113fa2016-09-05 23:23:24 +02002231 self.assertIsNotNone(sslobj.shared_ciphers())
Christian Heimes68771112017-09-05 21:55:40 -07002232 self.assertIsNotNone(sslobj.version())
Martin Panter3840b2a2016-03-27 01:53:46 +00002233 self.assertTrue(sslobj.getpeercert())
2234 if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
2235 self.assertTrue(sslobj.get_channel_binding('tls-unique'))
2236 try:
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002237 self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
Martin Panter3840b2a2016-03-27 01:53:46 +00002238 except ssl.SSLSyscallError:
2239 # If the server shuts down the TCP connection without sending a
2240 # secure shutdown message, this is reported as SSL_ERROR_SYSCALL
2241 pass
2242 self.assertRaises(ssl.SSLError, sslobj.write, b'foo')
2243
2244 def test_bio_read_write_data(self):
2245 sock = socket.socket(socket.AF_INET)
2246 self.addCleanup(sock.close)
2247 sock.connect(self.server_addr)
2248 incoming = ssl.MemoryBIO()
2249 outgoing = ssl.MemoryBIO()
Christian Heimes2875c602021-04-19 07:27:10 +02002250 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2251 ctx.check_hostname = False
Martin Panter3840b2a2016-03-27 01:53:46 +00002252 ctx.verify_mode = ssl.CERT_NONE
2253 sslobj = ctx.wrap_bio(incoming, outgoing, False)
2254 self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
2255 req = b'FOO\n'
2256 self.ssl_io_loop(sock, incoming, outgoing, sslobj.write, req)
2257 buf = self.ssl_io_loop(sock, incoming, outgoing, sslobj.read, 1024)
2258 self.assertEqual(buf, b'foo\n')
2259 self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002260
2261
Martin Panter3840b2a2016-03-27 01:53:46 +00002262class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002263
Martin Panter3840b2a2016-03-27 01:53:46 +00002264 def test_timeout_connect_ex(self):
2265 # Issue #12065: on a timeout, connect_ex() should return the original
2266 # errno (mimicking the behaviour of non-SSL sockets).
Serhiy Storchakabfb1cf42020-04-29 10:36:20 +03002267 with socket_helper.transient_internet(REMOTE_HOST):
Christian Heimesd0486372016-09-10 23:23:33 +02002268 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002269 cert_reqs=ssl.CERT_REQUIRED,
2270 do_handshake_on_connect=False)
2271 self.addCleanup(s.close)
2272 s.settimeout(0.0000001)
2273 rc = s.connect_ex((REMOTE_HOST, 443))
2274 if rc == 0:
2275 self.skipTest("REMOTE_HOST responded too quickly")
Carl Meyer29c451c2021-03-27 15:52:28 -06002276 elif rc == errno.ENETUNREACH:
2277 self.skipTest("Network unreachable.")
Martin Panter3840b2a2016-03-27 01:53:46 +00002278 self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK))
2279
Serhiy Storchaka16994912020-04-25 10:06:29 +03002280 @unittest.skipUnless(socket_helper.IPV6_ENABLED, 'Needs IPv6')
Martin Panter3840b2a2016-03-27 01:53:46 +00002281 def test_get_server_certificate_ipv6(self):
Serhiy Storchakabfb1cf42020-04-29 10:36:20 +03002282 with socket_helper.transient_internet('ipv6.google.com'):
Martin Panter3840b2a2016-03-27 01:53:46 +00002283 _test_get_server_certificate(self, 'ipv6.google.com', 443)
2284 _test_get_server_certificate_fail(self, 'ipv6.google.com', 443)
2285
Martin Panter3840b2a2016-03-27 01:53:46 +00002286
2287def _test_get_server_certificate(test, host, port, cert=None):
2288 pem = ssl.get_server_certificate((host, port))
2289 if not pem:
2290 test.fail("No server certificate on %s:%s!" % (host, port))
2291
2292 pem = ssl.get_server_certificate((host, port), ca_certs=cert)
2293 if not pem:
2294 test.fail("No server certificate on %s:%s!" % (host, port))
2295 if support.verbose:
2296 sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem))
2297
2298def _test_get_server_certificate_fail(test, host, port):
2299 try:
2300 pem = ssl.get_server_certificate((host, port), ca_certs=CERTFILE)
2301 except ssl.SSLError as x:
2302 #should fail
2303 if support.verbose:
2304 sys.stdout.write("%s\n" % x)
2305 else:
2306 test.fail("Got server certificate %s for %s:%s!" % (pem, host, port))
2307
2308
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002309from test.ssl_servers import make_https_server
Antoine Pitrou803e6d62010-10-13 10:36:15 +00002310
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002311class ThreadedEchoServer(threading.Thread):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002312
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002313 class ConnectionHandler(threading.Thread):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002314
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002315 """A mildly complicated class, because we want it to work both
2316 with and without the SSL wrapper around the socket connection, so
2317 that we can test the STARTTLS functionality."""
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002318
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002319 def __init__(self, server, connsock, addr):
2320 self.server = server
2321 self.running = False
2322 self.sock = connsock
2323 self.addr = addr
Serhiy Storchaka5eca7f32019-09-01 12:12:52 +03002324 self.sock.setblocking(True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002325 self.sslconn = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002326 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +00002327 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002328
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002329 def wrap_conn(self):
2330 try:
2331 self.sslconn = self.server.context.wrap_socket(
2332 self.sock, server_side=True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002333 self.server.selected_alpn_protocols.append(self.sslconn.selected_alpn_protocol())
Paul Monsonfb7e7502019-05-15 15:38:55 -07002334 except (ConnectionResetError, BrokenPipeError, ConnectionAbortedError) as e:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002335 # We treat ConnectionResetError as though it were an
2336 # SSLError - OpenSSL on Ubuntu abruptly closes the
2337 # connection when asked to use an unsupported protocol.
2338 #
Christian Heimes529525f2018-05-23 22:24:45 +02002339 # BrokenPipeError is raised in TLS 1.3 mode, when OpenSSL
2340 # tries to send session tickets after handshake.
2341 # https://github.com/openssl/openssl/issues/6342
Paul Monsonfb7e7502019-05-15 15:38:55 -07002342 #
2343 # ConnectionAbortedError is raised in TLS 1.3 mode, when OpenSSL
2344 # tries to send session tickets after handshake when using WinSock.
Christian Heimes529525f2018-05-23 22:24:45 +02002345 self.server.conn_errors.append(str(e))
2346 if self.server.chatty:
2347 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
2348 self.running = False
2349 self.close()
2350 return False
2351 except (ssl.SSLError, OSError) as e:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002352 # OSError may occur with wrong protocols, e.g. both
2353 # sides use PROTOCOL_TLS_SERVER.
2354 #
2355 # XXX Various errors can have happened here, for example
2356 # a mismatching protocol version, an invalid certificate,
2357 # or a low-level bug. This should be made more discriminating.
2358 #
2359 # bpo-31323: Store the exception as string to prevent
2360 # a reference leak: server -> conn_errors -> exception
2361 # -> traceback -> self (ConnectionHandler) -> server
2362 self.server.conn_errors.append(str(e))
2363 if self.server.chatty:
2364 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
2365 self.running = False
2366 self.server.stop()
2367 self.close()
2368 return False
2369 else:
2370 self.server.shared_ciphers.append(self.sslconn.shared_ciphers())
2371 if self.server.context.verify_mode == ssl.CERT_REQUIRED:
2372 cert = self.sslconn.getpeercert()
2373 if support.verbose and self.server.chatty:
2374 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
2375 cert_binary = self.sslconn.getpeercert(True)
2376 if support.verbose and self.server.chatty:
2377 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
2378 cipher = self.sslconn.cipher()
2379 if support.verbose and self.server.chatty:
2380 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002381 return True
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002382
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002383 def read(self):
2384 if self.sslconn:
2385 return self.sslconn.read()
2386 else:
2387 return self.sock.recv(1024)
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002388
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002389 def write(self, bytes):
2390 if self.sslconn:
2391 return self.sslconn.write(bytes)
2392 else:
2393 return self.sock.send(bytes)
2394
2395 def close(self):
2396 if self.sslconn:
2397 self.sslconn.close()
2398 else:
2399 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002400
Antoine Pitrou480a1242010-04-28 21:37:09 +00002401 def run(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002402 self.running = True
2403 if not self.server.starttls_server:
2404 if not self.wrap_conn():
2405 return
2406 while self.running:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002407 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002408 msg = self.read()
2409 stripped = msg.strip()
2410 if not stripped:
2411 # eof, so quit this handler
2412 self.running = False
2413 try:
2414 self.sock = self.sslconn.unwrap()
2415 except OSError:
2416 # Many tests shut the TCP connection down
2417 # without an SSL shutdown. This causes
2418 # unwrap() to raise OSError with errno=0!
2419 pass
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00002420 else:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002421 self.sslconn = None
2422 self.close()
2423 elif stripped == b'over':
2424 if support.verbose and self.server.connectionchatty:
2425 sys.stdout.write(" server: client closed connection\n")
2426 self.close()
2427 return
2428 elif (self.server.starttls_server and
2429 stripped == b'STARTTLS'):
2430 if support.verbose and self.server.connectionchatty:
2431 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
2432 self.write(b"OK\n")
2433 if not self.wrap_conn():
2434 return
2435 elif (self.server.starttls_server and self.sslconn
2436 and stripped == b'ENDTLS'):
2437 if support.verbose and self.server.connectionchatty:
2438 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
2439 self.write(b"OK\n")
2440 self.sock = self.sslconn.unwrap()
2441 self.sslconn = None
2442 if support.verbose and self.server.connectionchatty:
2443 sys.stdout.write(" server: connection is now unencrypted...\n")
2444 elif stripped == b'CB tls-unique':
2445 if support.verbose and self.server.connectionchatty:
2446 sys.stdout.write(" server: read CB tls-unique from client, sending our CB data...\n")
2447 data = self.sslconn.get_channel_binding("tls-unique")
2448 self.write(repr(data).encode("us-ascii") + b"\n")
Christian Heimes9fb051f2018-09-23 08:32:31 +02002449 elif stripped == b'PHA':
2450 if support.verbose and self.server.connectionchatty:
2451 sys.stdout.write(" server: initiating post handshake auth\n")
2452 try:
2453 self.sslconn.verify_client_post_handshake()
2454 except ssl.SSLError as e:
2455 self.write(repr(e).encode("us-ascii") + b"\n")
2456 else:
2457 self.write(b"OK\n")
2458 elif stripped == b'HASCERT':
2459 if self.sslconn.getpeercert() is not None:
2460 self.write(b'TRUE\n')
2461 else:
2462 self.write(b'FALSE\n')
2463 elif stripped == b'GETCERT':
2464 cert = self.sslconn.getpeercert()
2465 self.write(repr(cert).encode("us-ascii") + b"\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002466 else:
2467 if (support.verbose and
2468 self.server.connectionchatty):
2469 ctype = (self.sslconn and "encrypted") or "unencrypted"
2470 sys.stdout.write(" server: read %r (%s), sending back %r (%s)...\n"
2471 % (msg, ctype, msg.lower(), ctype))
2472 self.write(msg.lower())
Paul Monsonfb7e7502019-05-15 15:38:55 -07002473 except (ConnectionResetError, ConnectionAbortedError):
Christian Heimes529525f2018-05-23 22:24:45 +02002474 # XXX: OpenSSL 1.1.1 sometimes raises ConnectionResetError
2475 # when connection is not shut down gracefully.
2476 if self.server.chatty and support.verbose:
2477 sys.stdout.write(
2478 " Connection reset by peer: {}\n".format(
2479 self.addr)
2480 )
2481 self.close()
2482 self.running = False
Paul Monsonfb7e7502019-05-15 15:38:55 -07002483 except ssl.SSLError as err:
2484 # On Windows sometimes test_pha_required_nocert receives the
2485 # PEER_DID_NOT_RETURN_A_CERTIFICATE exception
2486 # before the 'tlsv13 alert certificate required' exception.
2487 # If the server is stopped when PEER_DID_NOT_RETURN_A_CERTIFICATE
2488 # is received test_pha_required_nocert fails with ConnectionResetError
2489 # because the underlying socket is closed
2490 if 'PEER_DID_NOT_RETURN_A_CERTIFICATE' == err.reason:
2491 if self.server.chatty and support.verbose:
2492 sys.stdout.write(err.args[1])
2493 # test_pha_required_nocert is expecting this exception
2494 raise ssl.SSLError('tlsv13 alert certificate required')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002495 except OSError:
2496 if self.server.chatty:
2497 handle_error("Test server failure:\n")
Bill Janssen2f5799b2008-06-29 00:08:12 +00002498 self.close()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002499 self.running = False
Christian Heimes529525f2018-05-23 22:24:45 +02002500
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002501 # normally, we'd just stop here, but for the test
2502 # harness, we want to stop the server
2503 self.server.stop()
Bill Janssen54cc54c2007-12-14 22:08:56 +00002504
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002505 def __init__(self, certificate=None, ssl_version=None,
2506 certreqs=None, cacerts=None,
2507 chatty=True, connectionchatty=False, starttls_server=False,
Christian Heimes2875c602021-04-19 07:27:10 +02002508 alpn_protocols=None,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002509 ciphers=None, context=None):
2510 if context:
2511 self.context = context
2512 else:
2513 self.context = ssl.SSLContext(ssl_version
2514 if ssl_version is not None
Christian Heimesa170fa12017-09-15 20:27:30 +02002515 else ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002516 self.context.verify_mode = (certreqs if certreqs is not None
2517 else ssl.CERT_NONE)
2518 if cacerts:
2519 self.context.load_verify_locations(cacerts)
2520 if certificate:
2521 self.context.load_cert_chain(certificate)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002522 if alpn_protocols:
2523 self.context.set_alpn_protocols(alpn_protocols)
2524 if ciphers:
2525 self.context.set_ciphers(ciphers)
2526 self.chatty = chatty
2527 self.connectionchatty = connectionchatty
2528 self.starttls_server = starttls_server
2529 self.sock = socket.socket()
Serhiy Storchaka16994912020-04-25 10:06:29 +03002530 self.port = socket_helper.bind_port(self.sock)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002531 self.flag = None
2532 self.active = False
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002533 self.selected_alpn_protocols = []
2534 self.shared_ciphers = []
2535 self.conn_errors = []
2536 threading.Thread.__init__(self)
2537 self.daemon = True
2538
2539 def __enter__(self):
2540 self.start(threading.Event())
2541 self.flag.wait()
2542 return self
2543
2544 def __exit__(self, *args):
2545 self.stop()
2546 self.join()
2547
2548 def start(self, flag=None):
2549 self.flag = flag
2550 threading.Thread.start(self)
2551
2552 def run(self):
2553 self.sock.settimeout(0.05)
2554 self.sock.listen()
2555 self.active = True
2556 if self.flag:
2557 # signal an event
2558 self.flag.set()
2559 while self.active:
2560 try:
2561 newconn, connaddr = self.sock.accept()
2562 if support.verbose and self.chatty:
2563 sys.stdout.write(' server: new connection from '
2564 + repr(connaddr) + '\n')
2565 handler = self.ConnectionHandler(self, newconn, connaddr)
2566 handler.start()
2567 handler.join()
Christian Heimes03c8ddd2020-11-20 09:26:07 +01002568 except TimeoutError:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002569 pass
2570 except KeyboardInterrupt:
2571 self.stop()
Christian Heimes529525f2018-05-23 22:24:45 +02002572 except BaseException as e:
2573 if support.verbose and self.chatty:
2574 sys.stdout.write(
2575 ' connection handling failed: ' + repr(e) + '\n')
2576
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002577 self.sock.close()
2578
2579 def stop(self):
2580 self.active = False
2581
2582class AsyncoreEchoServer(threading.Thread):
2583
2584 # this one's based on asyncore.dispatcher
2585
2586 class EchoServer (asyncore.dispatcher):
2587
2588 class ConnectionHandler(asyncore.dispatcher_with_send):
2589
2590 def __init__(self, conn, certfile):
2591 self.socket = test_wrap_socket(conn, server_side=True,
2592 certfile=certfile,
2593 do_handshake_on_connect=False)
2594 asyncore.dispatcher_with_send.__init__(self, self.socket)
2595 self._ssl_accepting = True
2596 self._do_ssl_handshake()
2597
2598 def readable(self):
2599 if isinstance(self.socket, ssl.SSLSocket):
2600 while self.socket.pending() > 0:
2601 self.handle_read_event()
2602 return True
2603
2604 def _do_ssl_handshake(self):
2605 try:
2606 self.socket.do_handshake()
2607 except (ssl.SSLWantReadError, ssl.SSLWantWriteError):
2608 return
2609 except ssl.SSLEOFError:
2610 return self.handle_close()
2611 except ssl.SSLError:
Bill Janssen54cc54c2007-12-14 22:08:56 +00002612 raise
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002613 except OSError as err:
2614 if err.args[0] == errno.ECONNABORTED:
2615 return self.handle_close()
2616 else:
2617 self._ssl_accepting = False
Bill Janssen54cc54c2007-12-14 22:08:56 +00002618
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002619 def handle_read(self):
2620 if self._ssl_accepting:
2621 self._do_ssl_handshake()
2622 else:
2623 data = self.recv(1024)
2624 if support.verbose:
2625 sys.stdout.write(" server: read %s from client\n" % repr(data))
2626 if not data:
2627 self.close()
2628 else:
2629 self.send(data.lower())
Bill Janssen54cc54c2007-12-14 22:08:56 +00002630
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002631 def handle_close(self):
2632 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002633 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002634 sys.stdout.write(" server: closed connection %s\n" % self.socket)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002635
2636 def handle_error(self):
2637 raise
2638
Trent Nelson78520002008-04-10 20:54:35 +00002639 def __init__(self, certfile):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002640 self.certfile = certfile
2641 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Serhiy Storchaka16994912020-04-25 10:06:29 +03002642 self.port = socket_helper.bind_port(sock, '')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002643 asyncore.dispatcher.__init__(self, sock)
2644 self.listen(5)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002645
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002646 def handle_accepted(self, sock_obj, addr):
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002647 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002648 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
2649 self.ConnectionHandler(sock_obj, self.certfile)
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002650
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002651 def handle_error(self):
2652 raise
Bill Janssen54cc54c2007-12-14 22:08:56 +00002653
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002654 def __init__(self, certfile):
2655 self.flag = None
2656 self.active = False
2657 self.server = self.EchoServer(certfile)
2658 self.port = self.server.port
2659 threading.Thread.__init__(self)
2660 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +00002661
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002662 def __str__(self):
2663 return "<%s %s>" % (self.__class__.__name__, self.server)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002664
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002665 def __enter__(self):
2666 self.start(threading.Event())
2667 self.flag.wait()
2668 return self
Thomas Woutersed03b412007-08-28 21:37:11 +00002669
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002670 def __exit__(self, *args):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002671 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002672 sys.stdout.write(" cleanup: stopping server.\n")
2673 self.stop()
2674 if support.verbose:
2675 sys.stdout.write(" cleanup: joining server thread.\n")
2676 self.join()
2677 if support.verbose:
2678 sys.stdout.write(" cleanup: successfully joined.\n")
2679 # make sure that ConnectionHandler is removed from socket_map
2680 asyncore.close_all(ignore_all=True)
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01002681
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002682 def start (self, flag=None):
2683 self.flag = flag
2684 threading.Thread.start(self)
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01002685
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002686 def run(self):
2687 self.active = True
2688 if self.flag:
2689 self.flag.set()
2690 while self.active:
Antoine Pitrou773b5db2010-04-27 08:53:36 +00002691 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002692 asyncore.loop(1)
2693 except:
2694 pass
Trent Nelson6b240cd2008-04-10 20:12:06 +00002695
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002696 def stop(self):
2697 self.active = False
2698 self.server.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002699
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002700def server_params_test(client_context, server_context, indata=b"FOO\n",
2701 chatty=True, connectionchatty=False, sni_name=None,
2702 session=None):
2703 """
2704 Launch a server, connect a client to it and try various reads
2705 and writes.
2706 """
2707 stats = {}
2708 server = ThreadedEchoServer(context=server_context,
2709 chatty=chatty,
2710 connectionchatty=False)
2711 with server:
2712 with client_context.wrap_socket(socket.socket(),
2713 server_hostname=sni_name, session=session) as s:
2714 s.connect((HOST, server.port))
2715 for arg in [indata, bytearray(indata), memoryview(indata)]:
2716 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002717 if support.verbose:
Antoine Pitrou18c913e2010-04-27 10:59:39 +00002718 sys.stdout.write(
Antoine Pitrou480a1242010-04-28 21:37:09 +00002719 " client: sending %r...\n" % indata)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002720 s.write(arg)
Antoine Pitrou18c913e2010-04-27 10:59:39 +00002721 outdata = s.read()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002722 if connectionchatty:
2723 if support.verbose:
2724 sys.stdout.write(" client: read %r\n" % outdata)
Trent Nelson6b240cd2008-04-10 20:12:06 +00002725 if outdata != indata.lower():
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002726 raise AssertionError(
Antoine Pitrou480a1242010-04-28 21:37:09 +00002727 "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
2728 % (outdata[:20], len(outdata),
2729 indata[:20].lower(), len(indata)))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002730 s.write(b"over\n")
2731 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002732 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00002733 sys.stdout.write(" client: closing connection.\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002734 stats.update({
2735 'compression': s.compression(),
2736 'cipher': s.cipher(),
2737 'peercert': s.getpeercert(),
2738 'client_alpn_protocol': s.selected_alpn_protocol(),
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002739 'version': s.version(),
2740 'session_reused': s.session_reused,
2741 'session': s.session,
2742 })
2743 s.close()
2744 stats['server_alpn_protocols'] = server.selected_alpn_protocols
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002745 stats['server_shared_ciphers'] = server.shared_ciphers
2746 return stats
Trent Nelson6b240cd2008-04-10 20:12:06 +00002747
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002748def try_protocol_combo(server_protocol, client_protocol, expect_success,
2749 certsreqs=None, server_options=0, client_options=0):
2750 """
2751 Try to SSL-connect using *client_protocol* to *server_protocol*.
2752 If *expect_success* is true, assert that the connection succeeds,
2753 if it's false, assert that the connection fails.
2754 Also, if *expect_success* is a string, assert that it is the protocol
2755 version actually used by the connection.
2756 """
2757 if certsreqs is None:
2758 certsreqs = ssl.CERT_NONE
2759 certtype = {
2760 ssl.CERT_NONE: "CERT_NONE",
2761 ssl.CERT_OPTIONAL: "CERT_OPTIONAL",
2762 ssl.CERT_REQUIRED: "CERT_REQUIRED",
2763 }[certsreqs]
2764 if support.verbose:
2765 formatstr = (expect_success and " %s->%s %s\n") or " {%s->%s} %s\n"
2766 sys.stdout.write(formatstr %
2767 (ssl.get_protocol_name(client_protocol),
2768 ssl.get_protocol_name(server_protocol),
2769 certtype))
Christian Heimes2875c602021-04-19 07:27:10 +02002770
2771 with warnings_helper.check_warnings():
2772 # ignore Deprecation warnings
2773 client_context = ssl.SSLContext(client_protocol)
2774 client_context.options |= client_options
2775 server_context = ssl.SSLContext(server_protocol)
2776 server_context.options |= server_options
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002777
Victor Stinner3ef63442019-02-19 18:06:03 +01002778 min_version = PROTOCOL_TO_TLS_VERSION.get(client_protocol, None)
2779 if (min_version is not None
Christian Heimes2875c602021-04-19 07:27:10 +02002780 # SSLContext.minimum_version is only available on recent OpenSSL
2781 # (setter added in OpenSSL 1.1.0, getter added in OpenSSL 1.1.1)
2782 and hasattr(server_context, 'minimum_version')
2783 and server_protocol == ssl.PROTOCOL_TLS
2784 and server_context.minimum_version > min_version
2785 ):
Victor Stinner3ef63442019-02-19 18:06:03 +01002786 # If OpenSSL configuration is strict and requires more recent TLS
2787 # version, we have to change the minimum to test old TLS versions.
Christian Heimes2875c602021-04-19 07:27:10 +02002788 with warnings_helper.check_warnings():
2789 server_context.minimum_version = min_version
Victor Stinner3ef63442019-02-19 18:06:03 +01002790
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002791 # NOTE: we must enable "ALL" ciphers on the client, otherwise an
2792 # SSLv23 client will send an SSLv3 hello (rather than SSLv2)
2793 # starting from OpenSSL 1.0.0 (see issue #8322).
Christian Heimesa170fa12017-09-15 20:27:30 +02002794 if client_context.protocol == ssl.PROTOCOL_TLS:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002795 client_context.set_ciphers("ALL")
2796
Christian Heimesf6c6b582021-03-18 23:06:50 +01002797 seclevel_workaround(server_context, client_context)
2798
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002799 for ctx in (client_context, server_context):
2800 ctx.verify_mode = certsreqs
Christian Heimesbd5c7d22018-01-20 15:16:30 +01002801 ctx.load_cert_chain(SIGNED_CERTFILE)
2802 ctx.load_verify_locations(SIGNING_CA)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002803 try:
2804 stats = server_params_test(client_context, server_context,
2805 chatty=False, connectionchatty=False)
2806 # Protocol mismatch can result in either an SSLError, or a
2807 # "Connection reset by peer" error.
2808 except ssl.SSLError:
2809 if expect_success:
2810 raise
2811 except OSError as e:
2812 if expect_success or e.errno != errno.ECONNRESET:
2813 raise
2814 else:
2815 if not expect_success:
2816 raise AssertionError(
2817 "Client protocol %s succeeded with server protocol %s!"
2818 % (ssl.get_protocol_name(client_protocol),
2819 ssl.get_protocol_name(server_protocol)))
2820 elif (expect_success is not True
2821 and expect_success != stats['version']):
2822 raise AssertionError("version mismatch: expected %r, got %r"
2823 % (expect_success, stats['version']))
2824
2825
2826class ThreadedTests(unittest.TestCase):
2827
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002828 def test_echo(self):
2829 """Basic test of an SSL client connecting to a server"""
2830 if support.verbose:
2831 sys.stdout.write("\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002832
Christian Heimesa170fa12017-09-15 20:27:30 +02002833 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002834
2835 with self.subTest(client=ssl.PROTOCOL_TLS_CLIENT, server=ssl.PROTOCOL_TLS_SERVER):
2836 server_params_test(client_context=client_context,
2837 server_context=server_context,
2838 chatty=True, connectionchatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02002839 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002840
2841 client_context.check_hostname = False
2842 with self.subTest(client=ssl.PROTOCOL_TLS_SERVER, server=ssl.PROTOCOL_TLS_CLIENT):
2843 with self.assertRaises(ssl.SSLError) as e:
2844 server_params_test(client_context=server_context,
2845 server_context=client_context,
2846 chatty=True, connectionchatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02002847 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002848 self.assertIn('called a function you should not call',
2849 str(e.exception))
2850
2851 with self.subTest(client=ssl.PROTOCOL_TLS_SERVER, server=ssl.PROTOCOL_TLS_SERVER):
2852 with self.assertRaises(ssl.SSLError) as e:
2853 server_params_test(client_context=server_context,
2854 server_context=server_context,
2855 chatty=True, connectionchatty=True)
2856 self.assertIn('called a function you should not call',
2857 str(e.exception))
2858
2859 with self.subTest(client=ssl.PROTOCOL_TLS_CLIENT, server=ssl.PROTOCOL_TLS_CLIENT):
2860 with self.assertRaises(ssl.SSLError) as e:
2861 server_params_test(client_context=server_context,
2862 server_context=client_context,
2863 chatty=True, connectionchatty=True)
2864 self.assertIn('called a function you should not call',
2865 str(e.exception))
2866
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002867 def test_getpeercert(self):
2868 if support.verbose:
2869 sys.stdout.write("\n")
Christian Heimesa170fa12017-09-15 20:27:30 +02002870
2871 client_context, server_context, hostname = testing_context()
2872 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002873 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002874 with client_context.wrap_socket(socket.socket(),
2875 do_handshake_on_connect=False,
2876 server_hostname=hostname) as s:
2877 s.connect((HOST, server.port))
2878 # getpeercert() raise ValueError while the handshake isn't
2879 # done.
2880 with self.assertRaises(ValueError):
2881 s.getpeercert()
2882 s.do_handshake()
2883 cert = s.getpeercert()
2884 self.assertTrue(cert, "Can't get peer certificate.")
2885 cipher = s.cipher()
2886 if support.verbose:
2887 sys.stdout.write(pprint.pformat(cert) + '\n')
2888 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
2889 if 'subject' not in cert:
2890 self.fail("No subject field in certificate: %s." %
2891 pprint.pformat(cert))
2892 if ((('organizationName', 'Python Software Foundation'),)
2893 not in cert['subject']):
2894 self.fail(
2895 "Missing or invalid 'organizationName' field in certificate subject; "
2896 "should be 'Python Software Foundation'.")
2897 self.assertIn('notBefore', cert)
2898 self.assertIn('notAfter', cert)
2899 before = ssl.cert_time_to_seconds(cert['notBefore'])
2900 after = ssl.cert_time_to_seconds(cert['notAfter'])
2901 self.assertLess(before, after)
Bill Janssen58afe4c2008-09-08 16:45:19 +00002902
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002903 def test_crl_check(self):
2904 if support.verbose:
2905 sys.stdout.write("\n")
2906
Christian Heimesa170fa12017-09-15 20:27:30 +02002907 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002908
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002909 tf = getattr(ssl, "VERIFY_X509_TRUSTED_FIRST", 0)
Christian Heimesa170fa12017-09-15 20:27:30 +02002910 self.assertEqual(client_context.verify_flags, ssl.VERIFY_DEFAULT | tf)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002911
2912 # VERIFY_DEFAULT should pass
2913 server = ThreadedEchoServer(context=server_context, chatty=True)
2914 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002915 with client_context.wrap_socket(socket.socket(),
2916 server_hostname=hostname) as s:
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002917 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002918 cert = s.getpeercert()
2919 self.assertTrue(cert, "Can't get peer certificate.")
Bill Janssen58afe4c2008-09-08 16:45:19 +00002920
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002921 # VERIFY_CRL_CHECK_LEAF without a loaded CRL file fails
Christian Heimesa170fa12017-09-15 20:27:30 +02002922 client_context.verify_flags |= ssl.VERIFY_CRL_CHECK_LEAF
Bill Janssen58afe4c2008-09-08 16:45:19 +00002923
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002924 server = ThreadedEchoServer(context=server_context, chatty=True)
2925 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002926 with client_context.wrap_socket(socket.socket(),
2927 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002928 with self.assertRaisesRegex(ssl.SSLError,
2929 "certificate verify failed"):
2930 s.connect((HOST, server.port))
Bill Janssen58afe4c2008-09-08 16:45:19 +00002931
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002932 # now load a CRL file. The CRL file is signed by the CA.
Christian Heimesa170fa12017-09-15 20:27:30 +02002933 client_context.load_verify_locations(CRLFILE)
Bill Janssen58afe4c2008-09-08 16:45:19 +00002934
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002935 server = ThreadedEchoServer(context=server_context, chatty=True)
2936 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002937 with client_context.wrap_socket(socket.socket(),
2938 server_hostname=hostname) as s:
Antoine Pitroub4bebda2014-04-29 10:03:28 +02002939 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002940 cert = s.getpeercert()
2941 self.assertTrue(cert, "Can't get peer certificate.")
Antoine Pitroub4bebda2014-04-29 10:03:28 +02002942
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002943 def test_check_hostname(self):
2944 if support.verbose:
2945 sys.stdout.write("\n")
Antoine Pitroub4bebda2014-04-29 10:03:28 +02002946
Christian Heimesa170fa12017-09-15 20:27:30 +02002947 client_context, server_context, hostname = testing_context()
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00002948
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002949 # correct hostname should verify
2950 server = ThreadedEchoServer(context=server_context, chatty=True)
2951 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002952 with client_context.wrap_socket(socket.socket(),
2953 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002954 s.connect((HOST, server.port))
2955 cert = s.getpeercert()
2956 self.assertTrue(cert, "Can't get peer certificate.")
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00002957
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002958 # incorrect hostname should raise an exception
2959 server = ThreadedEchoServer(context=server_context, chatty=True)
2960 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002961 with client_context.wrap_socket(socket.socket(),
2962 server_hostname="invalid") as s:
Christian Heimes61d478c2018-01-27 15:51:38 +01002963 with self.assertRaisesRegex(
2964 ssl.CertificateError,
2965 "Hostname mismatch, certificate is not valid for 'invalid'."):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002966 s.connect((HOST, server.port))
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00002967
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002968 # missing server_hostname arg should cause an exception, too
2969 server = ThreadedEchoServer(context=server_context, chatty=True)
2970 with server:
2971 with socket.socket() as s:
2972 with self.assertRaisesRegex(ValueError,
2973 "check_hostname requires server_hostname"):
Christian Heimesa170fa12017-09-15 20:27:30 +02002974 client_context.wrap_socket(s)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002975
Christian Heimesb467d9a2021-04-17 10:07:19 +02002976 @unittest.skipUnless(
2977 ssl.HAS_NEVER_CHECK_COMMON_NAME, "test requires hostname_checks_common_name"
2978 )
2979 def test_hostname_checks_common_name(self):
2980 client_context, server_context, hostname = testing_context()
2981 assert client_context.hostname_checks_common_name
2982 client_context.hostname_checks_common_name = False
2983
2984 # default cert has a SAN
2985 server = ThreadedEchoServer(context=server_context, chatty=True)
2986 with server:
2987 with client_context.wrap_socket(socket.socket(),
2988 server_hostname=hostname) as s:
2989 s.connect((HOST, server.port))
2990
2991 client_context, server_context, hostname = testing_context(NOSANFILE)
2992 client_context.hostname_checks_common_name = False
2993 server = ThreadedEchoServer(context=server_context, chatty=True)
2994 with server:
2995 with client_context.wrap_socket(socket.socket(),
2996 server_hostname=hostname) as s:
2997 with self.assertRaises(ssl.SSLCertVerificationError):
2998 s.connect((HOST, server.port))
2999
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003000 def test_ecc_cert(self):
3001 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3002 client_context.load_verify_locations(SIGNING_CA)
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003003 client_context.set_ciphers('ECDHE:ECDSA:!NULL:!aRSA')
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003004 hostname = SIGNED_CERTFILE_ECC_HOSTNAME
3005
3006 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3007 # load ECC cert
3008 server_context.load_cert_chain(SIGNED_CERTFILE_ECC)
3009
3010 # correct hostname should verify
3011 server = ThreadedEchoServer(context=server_context, chatty=True)
3012 with server:
3013 with client_context.wrap_socket(socket.socket(),
3014 server_hostname=hostname) as s:
3015 s.connect((HOST, server.port))
3016 cert = s.getpeercert()
3017 self.assertTrue(cert, "Can't get peer certificate.")
3018 cipher = s.cipher()[0].split('-')
3019 self.assertTrue(cipher[:2], ('ECDHE', 'ECDSA'))
3020
3021 def test_dual_rsa_ecc(self):
3022 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3023 client_context.load_verify_locations(SIGNING_CA)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003024 # TODO: fix TLSv1.3 once SSLContext can restrict signature
3025 # algorithms.
3026 client_context.options |= ssl.OP_NO_TLSv1_3
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003027 # only ECDSA certs
3028 client_context.set_ciphers('ECDHE:ECDSA:!NULL:!aRSA')
3029 hostname = SIGNED_CERTFILE_ECC_HOSTNAME
3030
3031 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3032 # load ECC and RSA key/cert pairs
3033 server_context.load_cert_chain(SIGNED_CERTFILE_ECC)
3034 server_context.load_cert_chain(SIGNED_CERTFILE)
3035
3036 # correct hostname should verify
3037 server = ThreadedEchoServer(context=server_context, chatty=True)
3038 with server:
3039 with client_context.wrap_socket(socket.socket(),
3040 server_hostname=hostname) as s:
3041 s.connect((HOST, server.port))
3042 cert = s.getpeercert()
3043 self.assertTrue(cert, "Can't get peer certificate.")
3044 cipher = s.cipher()[0].split('-')
3045 self.assertTrue(cipher[:2], ('ECDHE', 'ECDSA'))
3046
Christian Heimes66e57422018-01-29 14:25:13 +01003047 def test_check_hostname_idn(self):
3048 if support.verbose:
3049 sys.stdout.write("\n")
3050
Christian Heimes11a14932018-02-24 02:35:08 +01003051 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimes66e57422018-01-29 14:25:13 +01003052 server_context.load_cert_chain(IDNSANSFILE)
3053
Christian Heimes11a14932018-02-24 02:35:08 +01003054 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes66e57422018-01-29 14:25:13 +01003055 context.verify_mode = ssl.CERT_REQUIRED
3056 context.check_hostname = True
3057 context.load_verify_locations(SIGNING_CA)
3058
3059 # correct hostname should verify, when specified in several
3060 # different ways
3061 idn_hostnames = [
3062 ('könig.idn.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003063 'xn--knig-5qa.idn.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003064 ('xn--knig-5qa.idn.pythontest.net',
3065 'xn--knig-5qa.idn.pythontest.net'),
3066 (b'xn--knig-5qa.idn.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003067 'xn--knig-5qa.idn.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003068
3069 ('königsgäßchen.idna2003.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003070 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003071 ('xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
3072 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
3073 (b'xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003074 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
3075
3076 # ('königsgäßchen.idna2008.pythontest.net',
3077 # 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3078 ('xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
3079 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3080 (b'xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
3081 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3082
Christian Heimes66e57422018-01-29 14:25:13 +01003083 ]
3084 for server_hostname, expected_hostname in idn_hostnames:
3085 server = ThreadedEchoServer(context=server_context, chatty=True)
3086 with server:
3087 with context.wrap_socket(socket.socket(),
3088 server_hostname=server_hostname) as s:
3089 self.assertEqual(s.server_hostname, expected_hostname)
3090 s.connect((HOST, server.port))
3091 cert = s.getpeercert()
3092 self.assertEqual(s.server_hostname, expected_hostname)
3093 self.assertTrue(cert, "Can't get peer certificate.")
3094
Christian Heimes66e57422018-01-29 14:25:13 +01003095 # incorrect hostname should raise an exception
3096 server = ThreadedEchoServer(context=server_context, chatty=True)
3097 with server:
3098 with context.wrap_socket(socket.socket(),
3099 server_hostname="python.example.org") as s:
3100 with self.assertRaises(ssl.CertificateError):
3101 s.connect((HOST, server.port))
3102
Christian Heimes529525f2018-05-23 22:24:45 +02003103 def test_wrong_cert_tls12(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003104 """Connecting when the server rejects the client's certificate
3105
3106 Launch a server with CERT_REQUIRED, and check that trying to
3107 connect to it with a wrong client certificate fails.
3108 """
Christian Heimes05d9fe32018-02-27 08:55:39 +01003109 client_context, server_context, hostname = testing_context()
Christian Heimes88bfd0b2018-08-14 12:54:19 +02003110 # load client cert that is not signed by trusted CA
3111 client_context.load_cert_chain(CERTFILE)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003112 # require TLS client authentication
3113 server_context.verify_mode = ssl.CERT_REQUIRED
Christian Heimes529525f2018-05-23 22:24:45 +02003114 # TLS 1.3 has different handshake
3115 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimes05d9fe32018-02-27 08:55:39 +01003116
3117 server = ThreadedEchoServer(
3118 context=server_context, chatty=True, connectionchatty=True,
3119 )
3120
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003121 with server, \
Christian Heimes05d9fe32018-02-27 08:55:39 +01003122 client_context.wrap_socket(socket.socket(),
3123 server_hostname=hostname) as s:
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003124 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003125 # Expect either an SSL error about the server rejecting
3126 # the connection, or a low-level connection reset (which
3127 # sometimes happens on Windows)
3128 s.connect((HOST, server.port))
3129 except ssl.SSLError as e:
3130 if support.verbose:
3131 sys.stdout.write("\nSSLError is %r\n" % e)
3132 except OSError as e:
3133 if e.errno != errno.ECONNRESET:
3134 raise
3135 if support.verbose:
3136 sys.stdout.write("\nsocket.error is %r\n" % e)
3137 else:
3138 self.fail("Use of invalid cert should have failed!")
3139
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003140 @requires_tls_version('TLSv1_3')
Christian Heimes529525f2018-05-23 22:24:45 +02003141 def test_wrong_cert_tls13(self):
3142 client_context, server_context, hostname = testing_context()
Christian Heimes88bfd0b2018-08-14 12:54:19 +02003143 # load client cert that is not signed by trusted CA
3144 client_context.load_cert_chain(CERTFILE)
Christian Heimes529525f2018-05-23 22:24:45 +02003145 server_context.verify_mode = ssl.CERT_REQUIRED
3146 server_context.minimum_version = ssl.TLSVersion.TLSv1_3
3147 client_context.minimum_version = ssl.TLSVersion.TLSv1_3
3148
3149 server = ThreadedEchoServer(
3150 context=server_context, chatty=True, connectionchatty=True,
3151 )
3152 with server, \
3153 client_context.wrap_socket(socket.socket(),
3154 server_hostname=hostname) as s:
3155 # TLS 1.3 perform client cert exchange after handshake
3156 s.connect((HOST, server.port))
3157 try:
3158 s.write(b'data')
3159 s.read(4)
3160 except ssl.SSLError as e:
3161 if support.verbose:
3162 sys.stdout.write("\nSSLError is %r\n" % e)
3163 except OSError as e:
3164 if e.errno != errno.ECONNRESET:
3165 raise
3166 if support.verbose:
3167 sys.stdout.write("\nsocket.error is %r\n" % e)
3168 else:
3169 self.fail("Use of invalid cert should have failed!")
3170
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003171 def test_rude_shutdown(self):
3172 """A brutal shutdown of an SSL server should raise an OSError
3173 in the client when attempting handshake.
3174 """
3175 listener_ready = threading.Event()
3176 listener_gone = threading.Event()
3177
3178 s = socket.socket()
Serhiy Storchaka16994912020-04-25 10:06:29 +03003179 port = socket_helper.bind_port(s, HOST)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003180
3181 # `listener` runs in a thread. It sits in an accept() until
3182 # the main thread connects. Then it rudely closes the socket,
3183 # and sets Event `listener_gone` to let the main thread know
3184 # the socket is gone.
3185 def listener():
3186 s.listen()
3187 listener_ready.set()
3188 newsock, addr = s.accept()
3189 newsock.close()
3190 s.close()
3191 listener_gone.set()
3192
3193 def connector():
3194 listener_ready.wait()
3195 with socket.socket() as c:
3196 c.connect((HOST, port))
3197 listener_gone.wait()
Antoine Pitrou40f08742010-04-24 22:04:40 +00003198 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003199 ssl_sock = test_wrap_socket(c)
3200 except OSError:
3201 pass
3202 else:
3203 self.fail('connecting to closed SSL socket should have failed')
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003204
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003205 t = threading.Thread(target=listener)
3206 t.start()
3207 try:
3208 connector()
3209 finally:
Antoine Pitrou5c89b4e2012-11-11 01:25:36 +01003210 t.join()
Antoine Pitrou5c89b4e2012-11-11 01:25:36 +01003211
Christian Heimesb3ad0e52017-09-08 12:00:19 -07003212 def test_ssl_cert_verify_error(self):
3213 if support.verbose:
3214 sys.stdout.write("\n")
3215
3216 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3217 server_context.load_cert_chain(SIGNED_CERTFILE)
3218
3219 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3220
3221 server = ThreadedEchoServer(context=server_context, chatty=True)
3222 with server:
3223 with context.wrap_socket(socket.socket(),
Christian Heimesa170fa12017-09-15 20:27:30 +02003224 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Christian Heimesb3ad0e52017-09-08 12:00:19 -07003225 try:
3226 s.connect((HOST, server.port))
3227 except ssl.SSLError as e:
3228 msg = 'unable to get local issuer certificate'
3229 self.assertIsInstance(e, ssl.SSLCertVerificationError)
3230 self.assertEqual(e.verify_code, 20)
3231 self.assertEqual(e.verify_message, msg)
3232 self.assertIn(msg, repr(e))
3233 self.assertIn('certificate verify failed', repr(e))
3234
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003235 @requires_tls_version('SSLv2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003236 def test_protocol_sslv2(self):
3237 """Connecting to an SSLv2 server with various client options"""
3238 if support.verbose:
3239 sys.stdout.write("\n")
3240 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
3241 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
3242 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
Christian Heimesa170fa12017-09-15 20:27:30 +02003243 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003244 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003245 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
3246 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
3247 # SSLv23 client with specific SSL options
Christian Heimesa170fa12017-09-15 20:27:30 +02003248 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003249 client_options=ssl.OP_NO_SSLv3)
Christian Heimesa170fa12017-09-15 20:27:30 +02003250 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003251 client_options=ssl.OP_NO_TLSv1)
Antoine Pitrou242db722013-05-01 20:52:07 +02003252
Christian Heimesa170fa12017-09-15 20:27:30 +02003253 def test_PROTOCOL_TLS(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003254 """Connecting to an SSLv23 server with various client options"""
3255 if support.verbose:
3256 sys.stdout.write("\n")
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003257 if has_tls_version('SSLv2'):
Antoine Pitrou8f85f902012-01-03 22:46:48 +01003258 try:
Christian Heimesa170fa12017-09-15 20:27:30 +02003259 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv2, True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003260 except OSError as x:
3261 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
3262 if support.verbose:
3263 sys.stdout.write(
3264 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
3265 % str(x))
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003266 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003267 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False)
3268 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003269 if has_tls_version('TLSv1'):
3270 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1')
Antoine Pitrou8f85f902012-01-03 22:46:48 +01003271
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003272 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003273 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False, ssl.CERT_OPTIONAL)
3274 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True, ssl.CERT_OPTIONAL)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003275 if has_tls_version('TLSv1'):
3276 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003277
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003278 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003279 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False, ssl.CERT_REQUIRED)
3280 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True, ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003281 if has_tls_version('TLSv1'):
3282 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003283
3284 # Server with specific SSL options
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003285 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003286 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003287 server_options=ssl.OP_NO_SSLv3)
3288 # Will choose TLSv1
Christian Heimesa170fa12017-09-15 20:27:30 +02003289 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003290 server_options=ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003291 if has_tls_version('TLSv1'):
3292 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, False,
3293 server_options=ssl.OP_NO_TLSv1)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003294
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003295 @requires_tls_version('SSLv3')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003296 def test_protocol_sslv3(self):
3297 """Connecting to an SSLv3 server with various client options"""
3298 if support.verbose:
3299 sys.stdout.write("\n")
3300 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3')
3301 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_OPTIONAL)
3302 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003303 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003304 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003305 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003306 client_options=ssl.OP_NO_SSLv3)
3307 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003308
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003309 @requires_tls_version('TLSv1')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003310 def test_protocol_tlsv1(self):
3311 """Connecting to a TLSv1 server with various client options"""
3312 if support.verbose:
3313 sys.stdout.write("\n")
3314 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1')
3315 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL)
3316 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003317 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003318 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003319 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003320 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003321 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003322 client_options=ssl.OP_NO_TLSv1)
3323
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003324 @requires_tls_version('TLSv1_1')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003325 def test_protocol_tlsv1_1(self):
3326 """Connecting to a TLSv1.1 server with various client options.
3327 Testing against older TLS versions."""
3328 if support.verbose:
3329 sys.stdout.write("\n")
3330 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1')
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003331 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003332 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003333 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003334 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003335 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003336 client_options=ssl.OP_NO_TLSv1_1)
3337
Christian Heimesa170fa12017-09-15 20:27:30 +02003338 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1')
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003339 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False)
3340 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003341
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003342 @requires_tls_version('TLSv1_2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003343 def test_protocol_tlsv1_2(self):
3344 """Connecting to a TLSv1.2 server with various client options.
3345 Testing against older TLS versions."""
3346 if support.verbose:
3347 sys.stdout.write("\n")
3348 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2',
3349 server_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,
3350 client_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003351 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003352 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003353 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003354 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003355 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003356 client_options=ssl.OP_NO_TLSv1_2)
3357
Christian Heimesa170fa12017-09-15 20:27:30 +02003358 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003359 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1, False)
3360 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_2, False)
3361 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False)
3362 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False)
3363
3364 def test_starttls(self):
3365 """Switching from clear text to encrypted and back again."""
3366 msgs = (b"msg 1", b"MSG 2", b"STARTTLS", b"MSG 3", b"msg 4", b"ENDTLS", b"msg 5", b"msg 6")
3367
3368 server = ThreadedEchoServer(CERTFILE,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003369 starttls_server=True,
3370 chatty=True,
3371 connectionchatty=True)
3372 wrapped = False
3373 with server:
3374 s = socket.socket()
Serhiy Storchaka5eca7f32019-09-01 12:12:52 +03003375 s.setblocking(True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003376 s.connect((HOST, server.port))
Antoine Pitroud6494802011-07-21 01:11:30 +02003377 if support.verbose:
3378 sys.stdout.write("\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003379 for indata in msgs:
Antoine Pitroud6494802011-07-21 01:11:30 +02003380 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003381 sys.stdout.write(
3382 " client: sending %r...\n" % indata)
3383 if wrapped:
3384 conn.write(indata)
3385 outdata = conn.read()
3386 else:
3387 s.send(indata)
3388 outdata = s.recv(1024)
3389 msg = outdata.strip().lower()
3390 if indata == b"STARTTLS" and msg.startswith(b"ok"):
3391 # STARTTLS ok, switch to secure mode
3392 if support.verbose:
3393 sys.stdout.write(
3394 " client: read %r from server, starting TLS...\n"
3395 % msg)
Christian Heimesa170fa12017-09-15 20:27:30 +02003396 conn = test_wrap_socket(s)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003397 wrapped = True
3398 elif indata == b"ENDTLS" and msg.startswith(b"ok"):
3399 # ENDTLS ok, switch back to clear text
3400 if support.verbose:
3401 sys.stdout.write(
3402 " client: read %r from server, ending TLS...\n"
3403 % msg)
3404 s = conn.unwrap()
3405 wrapped = False
3406 else:
3407 if support.verbose:
3408 sys.stdout.write(
3409 " client: read %r from server\n" % msg)
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003410 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003411 sys.stdout.write(" client: closing connection.\n")
3412 if wrapped:
3413 conn.write(b"over\n")
3414 else:
3415 s.send(b"over\n")
3416 if wrapped:
3417 conn.close()
3418 else:
3419 s.close()
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003420
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003421 def test_socketserver(self):
3422 """Using socketserver to create and manage SSL connections."""
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003423 server = make_https_server(self, certfile=SIGNED_CERTFILE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003424 # try to connect
3425 if support.verbose:
3426 sys.stdout.write('\n')
3427 with open(CERTFILE, 'rb') as f:
3428 d1 = f.read()
3429 d2 = ''
3430 # now fetch the same data from the HTTPS server
3431 url = 'https://localhost:%d/%s' % (
3432 server.port, os.path.split(CERTFILE)[1])
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003433 context = ssl.create_default_context(cafile=SIGNING_CA)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003434 f = urllib.request.urlopen(url, context=context)
3435 try:
3436 dlen = f.info().get("content-length")
3437 if dlen and (int(dlen) > 0):
3438 d2 = f.read(int(dlen))
3439 if support.verbose:
3440 sys.stdout.write(
3441 " client: read %d bytes from remote server '%s'\n"
3442 % (len(d2), server))
3443 finally:
3444 f.close()
3445 self.assertEqual(d1, d2)
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003446
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003447 def test_asyncore_server(self):
3448 """Check the example asyncore integration."""
3449 if support.verbose:
3450 sys.stdout.write("\n")
Antoine Pitrou0e576f12011-12-22 10:03:38 +01003451
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003452 indata = b"FOO\n"
3453 server = AsyncoreEchoServer(CERTFILE)
3454 with server:
3455 s = test_wrap_socket(socket.socket())
3456 s.connect(('127.0.0.1', server.port))
3457 if support.verbose:
3458 sys.stdout.write(
3459 " client: sending %r...\n" % indata)
3460 s.write(indata)
3461 outdata = s.read()
3462 if support.verbose:
3463 sys.stdout.write(" client: read %r\n" % outdata)
3464 if outdata != indata.lower():
3465 self.fail(
3466 "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
3467 % (outdata[:20], len(outdata),
3468 indata[:20].lower(), len(indata)))
3469 s.write(b"over\n")
3470 if support.verbose:
3471 sys.stdout.write(" client: closing connection.\n")
3472 s.close()
3473 if support.verbose:
3474 sys.stdout.write(" client: connection closed.\n")
Benjamin Petersoncca27322015-01-23 16:35:37 -05003475
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003476 def test_recv_send(self):
3477 """Test recv(), send() and friends."""
3478 if support.verbose:
3479 sys.stdout.write("\n")
3480
3481 server = ThreadedEchoServer(CERTFILE,
3482 certreqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003483 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003484 cacerts=CERTFILE,
3485 chatty=True,
3486 connectionchatty=False)
3487 with server:
3488 s = test_wrap_socket(socket.socket(),
3489 server_side=False,
3490 certfile=CERTFILE,
3491 ca_certs=CERTFILE,
Christian Heimes2875c602021-04-19 07:27:10 +02003492 cert_reqs=ssl.CERT_NONE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003493 s.connect((HOST, server.port))
3494 # helper methods for standardising recv* method signatures
3495 def _recv_into():
3496 b = bytearray(b"\0"*100)
3497 count = s.recv_into(b)
3498 return b[:count]
3499
3500 def _recvfrom_into():
3501 b = bytearray(b"\0"*100)
3502 count, addr = s.recvfrom_into(b)
3503 return b[:count]
3504
3505 # (name, method, expect success?, *args, return value func)
3506 send_methods = [
3507 ('send', s.send, True, [], len),
3508 ('sendto', s.sendto, False, ["some.address"], len),
3509 ('sendall', s.sendall, True, [], lambda x: None),
3510 ]
3511 # (name, method, whether to expect success, *args)
3512 recv_methods = [
3513 ('recv', s.recv, True, []),
3514 ('recvfrom', s.recvfrom, False, ["some.address"]),
3515 ('recv_into', _recv_into, True, []),
3516 ('recvfrom_into', _recvfrom_into, False, []),
3517 ]
3518 data_prefix = "PREFIX_"
3519
3520 for (meth_name, send_meth, expect_success, args,
3521 ret_val_meth) in send_methods:
3522 indata = (data_prefix + meth_name).encode('ascii')
3523 try:
3524 ret = send_meth(indata, *args)
3525 msg = "sending with {}".format(meth_name)
3526 self.assertEqual(ret, ret_val_meth(indata), msg=msg)
3527 outdata = s.read()
3528 if outdata != indata.lower():
3529 self.fail(
3530 "While sending with <<{name:s}>> bad data "
3531 "<<{outdata:r}>> ({nout:d}) received; "
3532 "expected <<{indata:r}>> ({nin:d})\n".format(
3533 name=meth_name, outdata=outdata[:20],
3534 nout=len(outdata),
3535 indata=indata[:20], nin=len(indata)
3536 )
3537 )
3538 except ValueError as e:
3539 if expect_success:
3540 self.fail(
3541 "Failed to send with method <<{name:s}>>; "
3542 "expected to succeed.\n".format(name=meth_name)
3543 )
3544 if not str(e).startswith(meth_name):
3545 self.fail(
3546 "Method <<{name:s}>> failed with unexpected "
3547 "exception message: {exp:s}\n".format(
3548 name=meth_name, exp=e
3549 )
3550 )
3551
3552 for meth_name, recv_meth, expect_success, args in recv_methods:
3553 indata = (data_prefix + meth_name).encode('ascii')
3554 try:
3555 s.send(indata)
3556 outdata = recv_meth(*args)
3557 if outdata != indata.lower():
3558 self.fail(
3559 "While receiving with <<{name:s}>> bad data "
3560 "<<{outdata:r}>> ({nout:d}) received; "
3561 "expected <<{indata:r}>> ({nin:d})\n".format(
3562 name=meth_name, outdata=outdata[:20],
3563 nout=len(outdata),
3564 indata=indata[:20], nin=len(indata)
3565 )
3566 )
3567 except ValueError as e:
3568 if expect_success:
3569 self.fail(
3570 "Failed to receive with method <<{name:s}>>; "
3571 "expected to succeed.\n".format(name=meth_name)
3572 )
3573 if not str(e).startswith(meth_name):
3574 self.fail(
3575 "Method <<{name:s}>> failed with unexpected "
3576 "exception message: {exp:s}\n".format(
3577 name=meth_name, exp=e
3578 )
3579 )
3580 # consume data
3581 s.read()
3582
3583 # read(-1, buffer) is supported, even though read(-1) is not
3584 data = b"data"
3585 s.send(data)
3586 buffer = bytearray(len(data))
3587 self.assertEqual(s.read(-1, buffer), len(data))
3588 self.assertEqual(buffer, data)
3589
Christian Heimes888bbdc2017-09-07 14:18:21 -07003590 # sendall accepts bytes-like objects
3591 if ctypes is not None:
3592 ubyte = ctypes.c_ubyte * len(data)
3593 byteslike = ubyte.from_buffer_copy(data)
3594 s.sendall(byteslike)
3595 self.assertEqual(s.read(), data)
3596
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003597 # Make sure sendmsg et al are disallowed to avoid
3598 # inadvertent disclosure of data and/or corruption
3599 # of the encrypted data stream
Serhiy Storchaka42b1d612018-12-06 22:36:55 +02003600 self.assertRaises(NotImplementedError, s.dup)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003601 self.assertRaises(NotImplementedError, s.sendmsg, [b"data"])
3602 self.assertRaises(NotImplementedError, s.recvmsg, 100)
3603 self.assertRaises(NotImplementedError,
Serhiy Storchaka42b1d612018-12-06 22:36:55 +02003604 s.recvmsg_into, [bytearray(100)])
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003605 s.write(b"over\n")
3606
3607 self.assertRaises(ValueError, s.recv, -1)
3608 self.assertRaises(ValueError, s.read, -1)
3609
3610 s.close()
3611
3612 def test_recv_zero(self):
3613 server = ThreadedEchoServer(CERTFILE)
3614 server.__enter__()
3615 self.addCleanup(server.__exit__, None, None)
3616 s = socket.create_connection((HOST, server.port))
3617 self.addCleanup(s.close)
3618 s = test_wrap_socket(s, suppress_ragged_eofs=False)
3619 self.addCleanup(s.close)
3620
3621 # recv/read(0) should return no data
3622 s.send(b"data")
3623 self.assertEqual(s.recv(0), b"")
3624 self.assertEqual(s.read(0), b"")
3625 self.assertEqual(s.read(), b"data")
3626
3627 # Should not block if the other end sends no data
3628 s.setblocking(False)
3629 self.assertEqual(s.recv(0), b"")
3630 self.assertEqual(s.recv_into(bytearray()), 0)
3631
3632 def test_nonblocking_send(self):
3633 server = ThreadedEchoServer(CERTFILE,
3634 certreqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003635 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003636 cacerts=CERTFILE,
3637 chatty=True,
3638 connectionchatty=False)
3639 with server:
3640 s = test_wrap_socket(socket.socket(),
3641 server_side=False,
3642 certfile=CERTFILE,
3643 ca_certs=CERTFILE,
Christian Heimes2875c602021-04-19 07:27:10 +02003644 cert_reqs=ssl.CERT_NONE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003645 s.connect((HOST, server.port))
3646 s.setblocking(False)
3647
3648 # If we keep sending data, at some point the buffers
3649 # will be full and the call will block
3650 buf = bytearray(8192)
3651 def fill_buffer():
3652 while True:
3653 s.send(buf)
3654 self.assertRaises((ssl.SSLWantWriteError,
3655 ssl.SSLWantReadError), fill_buffer)
3656
3657 # Now read all the output and discard it
3658 s.setblocking(True)
3659 s.close()
3660
3661 def test_handshake_timeout(self):
3662 # Issue #5103: SSL handshake must respect the socket timeout
3663 server = socket.socket(socket.AF_INET)
3664 host = "127.0.0.1"
Serhiy Storchaka16994912020-04-25 10:06:29 +03003665 port = socket_helper.bind_port(server)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003666 started = threading.Event()
3667 finish = False
3668
3669 def serve():
3670 server.listen()
3671 started.set()
3672 conns = []
3673 while not finish:
3674 r, w, e = select.select([server], [], [], 0.1)
3675 if server in r:
3676 # Let the socket hang around rather than having
3677 # it closed by garbage collection.
3678 conns.append(server.accept()[0])
3679 for sock in conns:
3680 sock.close()
3681
3682 t = threading.Thread(target=serve)
3683 t.start()
3684 started.wait()
3685
3686 try:
3687 try:
3688 c = socket.socket(socket.AF_INET)
3689 c.settimeout(0.2)
3690 c.connect((host, port))
3691 # Will attempt handshake and time out
Christian Heimes03c8ddd2020-11-20 09:26:07 +01003692 self.assertRaisesRegex(TimeoutError, "timed out",
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003693 test_wrap_socket, c)
3694 finally:
3695 c.close()
3696 try:
3697 c = socket.socket(socket.AF_INET)
3698 c = test_wrap_socket(c)
3699 c.settimeout(0.2)
3700 # Will attempt handshake and time out
Christian Heimes03c8ddd2020-11-20 09:26:07 +01003701 self.assertRaisesRegex(TimeoutError, "timed out",
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003702 c.connect, (host, port))
3703 finally:
3704 c.close()
3705 finally:
3706 finish = True
3707 t.join()
3708 server.close()
3709
3710 def test_server_accept(self):
3711 # Issue #16357: accept() on a SSLSocket created through
3712 # SSLContext.wrap_socket().
Christian Heimes2875c602021-04-19 07:27:10 +02003713 client_ctx, server_ctx, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003714 server = socket.socket(socket.AF_INET)
3715 host = "127.0.0.1"
Serhiy Storchaka16994912020-04-25 10:06:29 +03003716 port = socket_helper.bind_port(server)
Christian Heimes2875c602021-04-19 07:27:10 +02003717 server = server_ctx.wrap_socket(server, server_side=True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003718 self.assertTrue(server.server_side)
3719
3720 evt = threading.Event()
3721 remote = None
3722 peer = None
3723 def serve():
3724 nonlocal remote, peer
3725 server.listen()
3726 # Block on the accept and wait on the connection to close.
3727 evt.set()
3728 remote, peer = server.accept()
Christian Heimes529525f2018-05-23 22:24:45 +02003729 remote.send(remote.recv(4))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003730
3731 t = threading.Thread(target=serve)
3732 t.start()
3733 # Client wait until server setup and perform a connect.
3734 evt.wait()
Christian Heimes2875c602021-04-19 07:27:10 +02003735 client = client_ctx.wrap_socket(
3736 socket.socket(), server_hostname=hostname
3737 )
3738 client.connect((hostname, port))
Christian Heimes529525f2018-05-23 22:24:45 +02003739 client.send(b'data')
3740 client.recv()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003741 client_addr = client.getsockname()
3742 client.close()
3743 t.join()
3744 remote.close()
3745 server.close()
3746 # Sanity checks.
3747 self.assertIsInstance(remote, ssl.SSLSocket)
3748 self.assertEqual(peer, client_addr)
3749
3750 def test_getpeercert_enotconn(self):
Christian Heimes2875c602021-04-19 07:27:10 +02003751 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3752 context.check_hostname = False
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003753 with context.wrap_socket(socket.socket()) as sock:
3754 with self.assertRaises(OSError) as cm:
3755 sock.getpeercert()
3756 self.assertEqual(cm.exception.errno, errno.ENOTCONN)
3757
3758 def test_do_handshake_enotconn(self):
Christian Heimes2875c602021-04-19 07:27:10 +02003759 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3760 context.check_hostname = False
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003761 with context.wrap_socket(socket.socket()) as sock:
3762 with self.assertRaises(OSError) as cm:
3763 sock.do_handshake()
3764 self.assertEqual(cm.exception.errno, errno.ENOTCONN)
3765
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003766 def test_no_shared_ciphers(self):
3767 client_context, server_context, hostname = testing_context()
3768 # OpenSSL enables all TLS 1.3 ciphers, enforce TLS 1.2 for test
3769 client_context.options |= ssl.OP_NO_TLSv1_3
Victor Stinner5e922652018-09-07 17:30:33 +02003770 # Force different suites on client and server
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003771 client_context.set_ciphers("AES128")
3772 server_context.set_ciphers("AES256")
3773 with ThreadedEchoServer(context=server_context) as server:
3774 with client_context.wrap_socket(socket.socket(),
3775 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003776 with self.assertRaises(OSError):
3777 s.connect((HOST, server.port))
3778 self.assertIn("no shared cipher", server.conn_errors[0])
3779
3780 def test_version_basic(self):
3781 """
3782 Basic tests for SSLSocket.version().
3783 More tests are done in the test_protocol_*() methods.
3784 """
Christian Heimesa170fa12017-09-15 20:27:30 +02003785 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3786 context.check_hostname = False
3787 context.verify_mode = ssl.CERT_NONE
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003788 with ThreadedEchoServer(CERTFILE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003789 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003790 chatty=False) as server:
3791 with context.wrap_socket(socket.socket()) as s:
3792 self.assertIs(s.version(), None)
Christian Heimes141c5e82018-02-24 21:10:57 +01003793 self.assertIs(s._sslobj, None)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003794 s.connect((HOST, server.port))
Christian Heimes39258d32021-04-17 11:36:35 +02003795 self.assertEqual(s.version(), 'TLSv1.3')
Christian Heimes141c5e82018-02-24 21:10:57 +01003796 self.assertIs(s._sslobj, None)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003797 self.assertIs(s.version(), None)
3798
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003799 @requires_tls_version('TLSv1_3')
Christian Heimescb5b68a2017-09-07 18:07:00 -07003800 def test_tls1_3(self):
Christian Heimes2875c602021-04-19 07:27:10 +02003801 client_context, server_context, hostname = testing_context()
3802 client_context.minimum_version = ssl.TLSVersion.TLSv1_3
3803 with ThreadedEchoServer(context=server_context) as server:
3804 with client_context.wrap_socket(socket.socket(),
3805 server_hostname=hostname) as s:
Christian Heimescb5b68a2017-09-07 18:07:00 -07003806 s.connect((HOST, server.port))
Christian Heimes05d9fe32018-02-27 08:55:39 +01003807 self.assertIn(s.cipher()[0], {
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003808 'TLS_AES_256_GCM_SHA384',
3809 'TLS_CHACHA20_POLY1305_SHA256',
3810 'TLS_AES_128_GCM_SHA256',
Christian Heimes05d9fe32018-02-27 08:55:39 +01003811 })
3812 self.assertEqual(s.version(), 'TLSv1.3')
Christian Heimescb5b68a2017-09-07 18:07:00 -07003813
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003814 @requires_tls_version('TLSv1_2')
Christian Heimes2875c602021-04-19 07:27:10 +02003815 @requires_tls_version('TLSv1')
3816 @ignore_deprecation
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003817 def test_min_max_version_tlsv1_2(self):
Christian Heimes698dde12018-02-27 11:54:43 +01003818 client_context, server_context, hostname = testing_context()
3819 # client TLSv1.0 to 1.2
3820 client_context.minimum_version = ssl.TLSVersion.TLSv1
3821 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
3822 # server only TLSv1.2
3823 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
3824 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
3825
3826 with ThreadedEchoServer(context=server_context) as server:
3827 with client_context.wrap_socket(socket.socket(),
3828 server_hostname=hostname) as s:
3829 s.connect((HOST, server.port))
3830 self.assertEqual(s.version(), 'TLSv1.2')
3831
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003832 @requires_tls_version('TLSv1_1')
Christian Heimes2875c602021-04-19 07:27:10 +02003833 @ignore_deprecation
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003834 def test_min_max_version_tlsv1_1(self):
3835 client_context, server_context, hostname = testing_context()
Christian Heimes698dde12018-02-27 11:54:43 +01003836 # client 1.0 to 1.2, server 1.0 to 1.1
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003837 client_context.minimum_version = ssl.TLSVersion.TLSv1
3838 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimes698dde12018-02-27 11:54:43 +01003839 server_context.minimum_version = ssl.TLSVersion.TLSv1
3840 server_context.maximum_version = ssl.TLSVersion.TLSv1_1
Christian Heimesf6c6b582021-03-18 23:06:50 +01003841 seclevel_workaround(client_context, server_context)
Christian Heimes698dde12018-02-27 11:54:43 +01003842
3843 with ThreadedEchoServer(context=server_context) as server:
3844 with client_context.wrap_socket(socket.socket(),
3845 server_hostname=hostname) as s:
3846 s.connect((HOST, server.port))
3847 self.assertEqual(s.version(), 'TLSv1.1')
3848
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003849 @requires_tls_version('TLSv1_2')
Christian Heimesce04e712020-11-18 13:10:53 +01003850 @requires_tls_version('TLSv1')
Christian Heimes2875c602021-04-19 07:27:10 +02003851 @ignore_deprecation
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003852 def test_min_max_version_mismatch(self):
3853 client_context, server_context, hostname = testing_context()
Christian Heimes698dde12018-02-27 11:54:43 +01003854 # client 1.0, server 1.2 (mismatch)
Christian Heimes698dde12018-02-27 11:54:43 +01003855 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesc9bc49c2019-09-11 19:24:47 +02003856 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
Christian Heimese35d1ba2019-06-03 20:40:15 +02003857 client_context.maximum_version = ssl.TLSVersion.TLSv1
Christian Heimesde606ea2019-09-11 19:48:58 +02003858 client_context.minimum_version = ssl.TLSVersion.TLSv1
Christian Heimesf6c6b582021-03-18 23:06:50 +01003859 seclevel_workaround(client_context, server_context)
3860
Christian Heimes698dde12018-02-27 11:54:43 +01003861 with ThreadedEchoServer(context=server_context) as server:
3862 with client_context.wrap_socket(socket.socket(),
3863 server_hostname=hostname) as s:
3864 with self.assertRaises(ssl.SSLError) as e:
3865 s.connect((HOST, server.port))
3866 self.assertIn("alert", str(e.exception))
3867
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003868 @requires_tls_version('SSLv3')
Christian Heimes698dde12018-02-27 11:54:43 +01003869 def test_min_max_version_sslv3(self):
3870 client_context, server_context, hostname = testing_context()
3871 server_context.minimum_version = ssl.TLSVersion.SSLv3
3872 client_context.minimum_version = ssl.TLSVersion.SSLv3
3873 client_context.maximum_version = ssl.TLSVersion.SSLv3
Christian Heimesf6c6b582021-03-18 23:06:50 +01003874 seclevel_workaround(client_context, server_context)
3875
Christian Heimes698dde12018-02-27 11:54:43 +01003876 with ThreadedEchoServer(context=server_context) as server:
3877 with client_context.wrap_socket(socket.socket(),
3878 server_hostname=hostname) as s:
3879 s.connect((HOST, server.port))
3880 self.assertEqual(s.version(), 'SSLv3')
3881
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003882 def test_default_ecdh_curve(self):
3883 # Issue #21015: elliptic curve-based Diffie Hellman key exchange
3884 # should be enabled by default on SSL contexts.
Christian Heimes2875c602021-04-19 07:27:10 +02003885 client_context, server_context, hostname = testing_context()
Christian Heimescb5b68a2017-09-07 18:07:00 -07003886 # TLSv1.3 defaults to PFS key agreement and no longer has KEA in
3887 # cipher name.
Christian Heimes2875c602021-04-19 07:27:10 +02003888 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003889 # Prior to OpenSSL 1.0.0, ECDH ciphers have to be enabled
3890 # explicitly using the 'ECCdraft' cipher alias. Otherwise,
3891 # our default cipher list should prefer ECDH-based ciphers
3892 # automatically.
Christian Heimes2875c602021-04-19 07:27:10 +02003893 with ThreadedEchoServer(context=server_context) as server:
3894 with client_context.wrap_socket(socket.socket(),
3895 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003896 s.connect((HOST, server.port))
3897 self.assertIn("ECDH", s.cipher()[0])
3898
3899 @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES,
3900 "'tls-unique' channel binding not available")
3901 def test_tls_unique_channel_binding(self):
3902 """Test tls-unique channel binding."""
3903 if support.verbose:
3904 sys.stdout.write("\n")
3905
Christian Heimes05d9fe32018-02-27 08:55:39 +01003906 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01003907
3908 server = ThreadedEchoServer(context=server_context,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003909 chatty=True,
3910 connectionchatty=False)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003911
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003912 with server:
Christian Heimes05d9fe32018-02-27 08:55:39 +01003913 with client_context.wrap_socket(
3914 socket.socket(),
3915 server_hostname=hostname) as s:
3916 s.connect((HOST, server.port))
3917 # get the data
3918 cb_data = s.get_channel_binding("tls-unique")
3919 if support.verbose:
3920 sys.stdout.write(
3921 " got channel binding data: {0!r}\n".format(cb_data))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003922
Christian Heimes05d9fe32018-02-27 08:55:39 +01003923 # check if it is sane
3924 self.assertIsNotNone(cb_data)
Christian Heimes529525f2018-05-23 22:24:45 +02003925 if s.version() == 'TLSv1.3':
3926 self.assertEqual(len(cb_data), 48)
3927 else:
3928 self.assertEqual(len(cb_data), 12) # True for TLSv1
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003929
Christian Heimes05d9fe32018-02-27 08:55:39 +01003930 # and compare with the peers version
3931 s.write(b"CB tls-unique\n")
3932 peer_data_repr = s.read().strip()
3933 self.assertEqual(peer_data_repr,
3934 repr(cb_data).encode("us-ascii"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003935
3936 # now, again
Christian Heimes05d9fe32018-02-27 08:55:39 +01003937 with client_context.wrap_socket(
3938 socket.socket(),
3939 server_hostname=hostname) as s:
3940 s.connect((HOST, server.port))
3941 new_cb_data = s.get_channel_binding("tls-unique")
3942 if support.verbose:
3943 sys.stdout.write(
3944 "got another channel binding data: {0!r}\n".format(
3945 new_cb_data)
3946 )
3947 # is it really unique
3948 self.assertNotEqual(cb_data, new_cb_data)
3949 self.assertIsNotNone(cb_data)
Christian Heimes529525f2018-05-23 22:24:45 +02003950 if s.version() == 'TLSv1.3':
3951 self.assertEqual(len(cb_data), 48)
3952 else:
3953 self.assertEqual(len(cb_data), 12) # True for TLSv1
Christian Heimes05d9fe32018-02-27 08:55:39 +01003954 s.write(b"CB tls-unique\n")
3955 peer_data_repr = s.read().strip()
3956 self.assertEqual(peer_data_repr,
3957 repr(new_cb_data).encode("us-ascii"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003958
3959 def test_compression(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02003960 client_context, server_context, hostname = testing_context()
3961 stats = server_params_test(client_context, server_context,
3962 chatty=True, connectionchatty=True,
3963 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003964 if support.verbose:
3965 sys.stdout.write(" got compression: {!r}\n".format(stats['compression']))
3966 self.assertIn(stats['compression'], { None, 'ZLIB', 'RLE' })
3967
3968 @unittest.skipUnless(hasattr(ssl, 'OP_NO_COMPRESSION'),
3969 "ssl.OP_NO_COMPRESSION needed for this test")
3970 def test_compression_disabled(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02003971 client_context, server_context, hostname = testing_context()
3972 client_context.options |= ssl.OP_NO_COMPRESSION
3973 server_context.options |= ssl.OP_NO_COMPRESSION
3974 stats = server_params_test(client_context, server_context,
3975 chatty=True, connectionchatty=True,
3976 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003977 self.assertIs(stats['compression'], None)
3978
Paul Monsonf3550692019-06-19 13:09:54 -07003979 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003980 def test_dh_params(self):
3981 # Check we can get a connection with ephemeral Diffie-Hellman
Christian Heimesa170fa12017-09-15 20:27:30 +02003982 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01003983 # test scenario needs TLS <= 1.2
3984 client_context.options |= ssl.OP_NO_TLSv1_3
Christian Heimesa170fa12017-09-15 20:27:30 +02003985 server_context.load_dh_params(DHFILE)
3986 server_context.set_ciphers("kEDH")
Christian Heimes05d9fe32018-02-27 08:55:39 +01003987 server_context.options |= ssl.OP_NO_TLSv1_3
Christian Heimesa170fa12017-09-15 20:27:30 +02003988 stats = server_params_test(client_context, server_context,
3989 chatty=True, connectionchatty=True,
3990 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003991 cipher = stats["cipher"][0]
3992 parts = cipher.split("-")
3993 if "ADH" not in parts and "EDH" not in parts and "DHE" not in parts:
3994 self.fail("Non-DH cipher: " + cipher[0])
3995
Christian Heimesb7b92252018-02-25 09:49:31 +01003996 def test_ecdh_curve(self):
3997 # server secp384r1, client auto
3998 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01003999
Christian Heimesb7b92252018-02-25 09:49:31 +01004000 server_context.set_ecdh_curve("secp384r1")
4001 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
Christian Heimesd37b74f2021-04-19 08:31:29 +02004002 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesb7b92252018-02-25 09:49:31 +01004003 stats = server_params_test(client_context, server_context,
4004 chatty=True, connectionchatty=True,
4005 sni_name=hostname)
4006
4007 # server auto, client secp384r1
4008 client_context, server_context, hostname = testing_context()
4009 client_context.set_ecdh_curve("secp384r1")
4010 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
Christian Heimesd37b74f2021-04-19 08:31:29 +02004011 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesb7b92252018-02-25 09:49:31 +01004012 stats = server_params_test(client_context, server_context,
4013 chatty=True, connectionchatty=True,
4014 sni_name=hostname)
4015
4016 # server / client curve mismatch
4017 client_context, server_context, hostname = testing_context()
4018 client_context.set_ecdh_curve("prime256v1")
4019 server_context.set_ecdh_curve("secp384r1")
4020 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
Christian Heimesd37b74f2021-04-19 08:31:29 +02004021 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
4022 with self.assertRaises(ssl.SSLError):
Christian Heimes39258d32021-04-17 11:36:35 +02004023 server_params_test(client_context, server_context,
4024 chatty=True, connectionchatty=True,
4025 sni_name=hostname)
Christian Heimesb7b92252018-02-25 09:49:31 +01004026
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004027 def test_selected_alpn_protocol(self):
4028 # selected_alpn_protocol() is None unless ALPN is used.
Christian Heimesa170fa12017-09-15 20:27:30 +02004029 client_context, server_context, hostname = testing_context()
4030 stats = server_params_test(client_context, server_context,
4031 chatty=True, connectionchatty=True,
4032 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004033 self.assertIs(stats['client_alpn_protocol'], None)
4034
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004035 def test_selected_alpn_protocol_if_server_uses_alpn(self):
4036 # selected_alpn_protocol() is None unless ALPN is used by the client.
Christian Heimesa170fa12017-09-15 20:27:30 +02004037 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004038 server_context.set_alpn_protocols(['foo', 'bar'])
4039 stats = server_params_test(client_context, server_context,
Christian Heimesa170fa12017-09-15 20:27:30 +02004040 chatty=True, connectionchatty=True,
4041 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004042 self.assertIs(stats['client_alpn_protocol'], None)
4043
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004044 def test_alpn_protocols(self):
4045 server_protocols = ['foo', 'bar', 'milkshake']
4046 protocol_tests = [
4047 (['foo', 'bar'], 'foo'),
4048 (['bar', 'foo'], 'foo'),
4049 (['milkshake'], 'milkshake'),
4050 (['http/3.0', 'http/4.0'], None)
4051 ]
4052 for client_protocols, expected in protocol_tests:
Christian Heimesa170fa12017-09-15 20:27:30 +02004053 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004054 server_context.set_alpn_protocols(server_protocols)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004055 client_context.set_alpn_protocols(client_protocols)
4056
4057 try:
4058 stats = server_params_test(client_context,
4059 server_context,
4060 chatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02004061 connectionchatty=True,
4062 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004063 except ssl.SSLError as e:
4064 stats = e
4065
Christian Heimes39258d32021-04-17 11:36:35 +02004066 msg = "failed trying %s (s) and %s (c).\n" \
4067 "was expecting %s, but got %%s from the %%s" \
4068 % (str(server_protocols), str(client_protocols),
4069 str(expected))
4070 client_result = stats['client_alpn_protocol']
4071 self.assertEqual(client_result, expected,
4072 msg % (client_result, "client"))
4073 server_result = stats['server_alpn_protocols'][-1] \
4074 if len(stats['server_alpn_protocols']) else 'nothing'
4075 self.assertEqual(server_result, expected,
4076 msg % (server_result, "server"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004077
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004078 def test_npn_protocols(self):
Christian Heimes39258d32021-04-17 11:36:35 +02004079 assert not ssl.HAS_NPN
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004080
4081 def sni_contexts(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004082 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004083 server_context.load_cert_chain(SIGNED_CERTFILE)
Christian Heimesa170fa12017-09-15 20:27:30 +02004084 other_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004085 other_context.load_cert_chain(SIGNED_CERTFILE2)
Christian Heimesa170fa12017-09-15 20:27:30 +02004086 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004087 client_context.load_verify_locations(SIGNING_CA)
4088 return server_context, other_context, client_context
4089
4090 def check_common_name(self, stats, name):
4091 cert = stats['peercert']
4092 self.assertIn((('commonName', name),), cert['subject'])
4093
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004094 def test_sni_callback(self):
4095 calls = []
4096 server_context, other_context, client_context = self.sni_contexts()
4097
Christian Heimesa170fa12017-09-15 20:27:30 +02004098 client_context.check_hostname = False
4099
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004100 def servername_cb(ssl_sock, server_name, initial_context):
4101 calls.append((server_name, initial_context))
4102 if server_name is not None:
4103 ssl_sock.context = other_context
4104 server_context.set_servername_callback(servername_cb)
4105
4106 stats = server_params_test(client_context, server_context,
4107 chatty=True,
4108 sni_name='supermessage')
4109 # The hostname was fetched properly, and the certificate was
4110 # changed for the connection.
4111 self.assertEqual(calls, [("supermessage", server_context)])
4112 # CERTFILE4 was selected
4113 self.check_common_name(stats, 'fakehostname')
4114
4115 calls = []
4116 # The callback is called with server_name=None
4117 stats = server_params_test(client_context, server_context,
4118 chatty=True,
4119 sni_name=None)
4120 self.assertEqual(calls, [(None, server_context)])
Christian Heimesa170fa12017-09-15 20:27:30 +02004121 self.check_common_name(stats, SIGNED_CERTFILE_HOSTNAME)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004122
4123 # Check disabling the callback
4124 calls = []
4125 server_context.set_servername_callback(None)
4126
4127 stats = server_params_test(client_context, server_context,
4128 chatty=True,
4129 sni_name='notfunny')
4130 # Certificate didn't change
Christian Heimesa170fa12017-09-15 20:27:30 +02004131 self.check_common_name(stats, SIGNED_CERTFILE_HOSTNAME)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004132 self.assertEqual(calls, [])
4133
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004134 def test_sni_callback_alert(self):
4135 # Returning a TLS alert is reflected to the connecting client
4136 server_context, other_context, client_context = self.sni_contexts()
4137
4138 def cb_returning_alert(ssl_sock, server_name, initial_context):
4139 return ssl.ALERT_DESCRIPTION_ACCESS_DENIED
4140 server_context.set_servername_callback(cb_returning_alert)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004141 with self.assertRaises(ssl.SSLError) as cm:
4142 stats = server_params_test(client_context, server_context,
4143 chatty=False,
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004144 sni_name='supermessage')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004145 self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_ACCESS_DENIED')
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004146
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004147 def test_sni_callback_raising(self):
4148 # Raising fails the connection with a TLS handshake failure alert.
4149 server_context, other_context, client_context = self.sni_contexts()
4150
4151 def cb_raising(ssl_sock, server_name, initial_context):
4152 1/0
4153 server_context.set_servername_callback(cb_raising)
4154
Victor Stinner00253502019-06-03 03:51:43 +02004155 with support.catch_unraisable_exception() as catch:
4156 with self.assertRaises(ssl.SSLError) as cm:
4157 stats = server_params_test(client_context, server_context,
4158 chatty=False,
4159 sni_name='supermessage')
4160
4161 self.assertEqual(cm.exception.reason,
4162 'SSLV3_ALERT_HANDSHAKE_FAILURE')
4163 self.assertEqual(catch.unraisable.exc_type, ZeroDivisionError)
Antoine Pitrou50b24d02013-04-11 20:48:42 +02004164
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004165 def test_sni_callback_wrong_return_type(self):
4166 # Returning the wrong return type terminates the TLS connection
4167 # with an internal error alert.
4168 server_context, other_context, client_context = self.sni_contexts()
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004169
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004170 def cb_wrong_return_type(ssl_sock, server_name, initial_context):
4171 return "foo"
4172 server_context.set_servername_callback(cb_wrong_return_type)
4173
Victor Stinner00253502019-06-03 03:51:43 +02004174 with support.catch_unraisable_exception() as catch:
4175 with self.assertRaises(ssl.SSLError) as cm:
4176 stats = server_params_test(client_context, server_context,
4177 chatty=False,
4178 sni_name='supermessage')
4179
4180
4181 self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_INTERNAL_ERROR')
4182 self.assertEqual(catch.unraisable.exc_type, TypeError)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004183
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004184 def test_shared_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004185 client_context, server_context, hostname = testing_context()
Christian Heimese8eb6cb2018-05-22 22:50:12 +02004186 client_context.set_ciphers("AES128:AES256")
4187 server_context.set_ciphers("AES256")
4188 expected_algs = [
4189 "AES256", "AES-256",
4190 # TLS 1.3 ciphers are always enabled
4191 "TLS_CHACHA20", "TLS_AES",
4192 ]
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004193
Christian Heimesa170fa12017-09-15 20:27:30 +02004194 stats = server_params_test(client_context, server_context,
4195 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004196 ciphers = stats['server_shared_ciphers'][0]
4197 self.assertGreater(len(ciphers), 0)
4198 for name, tls_version, bits in ciphers:
Christian Heimese8eb6cb2018-05-22 22:50:12 +02004199 if not any(alg in name for alg in expected_algs):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004200 self.fail(name)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004201
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004202 def test_read_write_after_close_raises_valuerror(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004203 client_context, server_context, hostname = testing_context()
4204 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004205
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004206 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02004207 s = client_context.wrap_socket(socket.socket(),
4208 server_hostname=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004209 s.connect((HOST, server.port))
4210 s.close()
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004211
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004212 self.assertRaises(ValueError, s.read, 1024)
4213 self.assertRaises(ValueError, s.write, b'hello')
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004214
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004215 def test_sendfile(self):
4216 TEST_DATA = b"x" * 512
Hai Shia7f5d932020-08-04 00:41:24 +08004217 with open(os_helper.TESTFN, 'wb') as f:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004218 f.write(TEST_DATA)
Hai Shia7f5d932020-08-04 00:41:24 +08004219 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimes2875c602021-04-19 07:27:10 +02004220 client_context, server_context, hostname = testing_context()
4221 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004222 with server:
Christian Heimes2875c602021-04-19 07:27:10 +02004223 with client_context.wrap_socket(socket.socket(),
4224 server_hostname=hostname) as s:
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004225 s.connect((HOST, server.port))
Hai Shia7f5d932020-08-04 00:41:24 +08004226 with open(os_helper.TESTFN, 'rb') as file:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004227 s.sendfile(file)
4228 self.assertEqual(s.recv(1024), TEST_DATA)
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004229
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004230 def test_session(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004231 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004232 # TODO: sessions aren't compatible with TLSv1.3 yet
4233 client_context.options |= ssl.OP_NO_TLSv1_3
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004234
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004235 # first connection without session
Christian Heimesa170fa12017-09-15 20:27:30 +02004236 stats = server_params_test(client_context, server_context,
4237 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004238 session = stats['session']
4239 self.assertTrue(session.id)
4240 self.assertGreater(session.time, 0)
4241 self.assertGreater(session.timeout, 0)
4242 self.assertTrue(session.has_ticket)
Christian Heimes39258d32021-04-17 11:36:35 +02004243 self.assertGreater(session.ticket_lifetime_hint, 0)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004244 self.assertFalse(stats['session_reused'])
4245 sess_stat = server_context.session_stats()
4246 self.assertEqual(sess_stat['accept'], 1)
4247 self.assertEqual(sess_stat['hits'], 0)
Giampaolo Rodola'915d1412014-06-11 03:54:30 +02004248
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004249 # reuse session
Christian Heimesa170fa12017-09-15 20:27:30 +02004250 stats = server_params_test(client_context, server_context,
4251 session=session, sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004252 sess_stat = server_context.session_stats()
4253 self.assertEqual(sess_stat['accept'], 2)
4254 self.assertEqual(sess_stat['hits'], 1)
4255 self.assertTrue(stats['session_reused'])
4256 session2 = stats['session']
4257 self.assertEqual(session2.id, session.id)
4258 self.assertEqual(session2, session)
4259 self.assertIsNot(session2, session)
4260 self.assertGreaterEqual(session2.time, session.time)
4261 self.assertGreaterEqual(session2.timeout, session.timeout)
Christian Heimes99a65702016-09-10 23:44:53 +02004262
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004263 # another one without session
Christian Heimesa170fa12017-09-15 20:27:30 +02004264 stats = server_params_test(client_context, server_context,
4265 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004266 self.assertFalse(stats['session_reused'])
4267 session3 = stats['session']
4268 self.assertNotEqual(session3.id, session.id)
4269 self.assertNotEqual(session3, session)
4270 sess_stat = server_context.session_stats()
4271 self.assertEqual(sess_stat['accept'], 3)
4272 self.assertEqual(sess_stat['hits'], 1)
Christian Heimes99a65702016-09-10 23:44:53 +02004273
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004274 # reuse session again
Christian Heimesa170fa12017-09-15 20:27:30 +02004275 stats = server_params_test(client_context, server_context,
4276 session=session, sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004277 self.assertTrue(stats['session_reused'])
4278 session4 = stats['session']
4279 self.assertEqual(session4.id, session.id)
4280 self.assertEqual(session4, session)
4281 self.assertGreaterEqual(session4.time, session.time)
4282 self.assertGreaterEqual(session4.timeout, session.timeout)
4283 sess_stat = server_context.session_stats()
4284 self.assertEqual(sess_stat['accept'], 4)
4285 self.assertEqual(sess_stat['hits'], 2)
Christian Heimes99a65702016-09-10 23:44:53 +02004286
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004287 def test_session_handling(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004288 client_context, server_context, hostname = testing_context()
4289 client_context2, _, _ = testing_context()
Christian Heimes99a65702016-09-10 23:44:53 +02004290
Christian Heimes05d9fe32018-02-27 08:55:39 +01004291 # TODO: session reuse does not work with TLSv1.3
Christian Heimesa170fa12017-09-15 20:27:30 +02004292 client_context.options |= ssl.OP_NO_TLSv1_3
4293 client_context2.options |= ssl.OP_NO_TLSv1_3
Christian Heimescb5b68a2017-09-07 18:07:00 -07004294
Christian Heimesa170fa12017-09-15 20:27:30 +02004295 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004296 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02004297 with client_context.wrap_socket(socket.socket(),
4298 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004299 # session is None before handshake
4300 self.assertEqual(s.session, None)
4301 self.assertEqual(s.session_reused, None)
4302 s.connect((HOST, server.port))
4303 session = s.session
4304 self.assertTrue(session)
4305 with self.assertRaises(TypeError) as e:
4306 s.session = object
Ned Deily4531ec72018-06-11 20:26:28 -04004307 self.assertEqual(str(e.exception), 'Value is not a SSLSession.')
Christian Heimes99a65702016-09-10 23:44:53 +02004308
Christian Heimesa170fa12017-09-15 20:27:30 +02004309 with client_context.wrap_socket(socket.socket(),
4310 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004311 s.connect((HOST, server.port))
4312 # cannot set session after handshake
4313 with self.assertRaises(ValueError) as e:
4314 s.session = session
4315 self.assertEqual(str(e.exception),
4316 'Cannot set session after handshake.')
Christian Heimes99a65702016-09-10 23:44:53 +02004317
Christian Heimesa170fa12017-09-15 20:27:30 +02004318 with client_context.wrap_socket(socket.socket(),
4319 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004320 # can set session before handshake and before the
4321 # connection was established
4322 s.session = session
4323 s.connect((HOST, server.port))
4324 self.assertEqual(s.session.id, session.id)
4325 self.assertEqual(s.session, session)
4326 self.assertEqual(s.session_reused, True)
Christian Heimes99a65702016-09-10 23:44:53 +02004327
Christian Heimesa170fa12017-09-15 20:27:30 +02004328 with client_context2.wrap_socket(socket.socket(),
4329 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004330 # cannot re-use session with a different SSLContext
4331 with self.assertRaises(ValueError) as e:
Christian Heimes99a65702016-09-10 23:44:53 +02004332 s.session = session
4333 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004334 self.assertEqual(str(e.exception),
4335 'Session refers to a different SSLContext.')
Christian Heimes99a65702016-09-10 23:44:53 +02004336
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01004337
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02004338@unittest.skipUnless(has_tls_version('TLSv1_3'), "Test needs TLS 1.3")
Christian Heimes9fb051f2018-09-23 08:32:31 +02004339class TestPostHandshakeAuth(unittest.TestCase):
4340 def test_pha_setter(self):
4341 protocols = [
Christian Heimes2875c602021-04-19 07:27:10 +02004342 ssl.PROTOCOL_TLS_SERVER, ssl.PROTOCOL_TLS_CLIENT
Christian Heimes9fb051f2018-09-23 08:32:31 +02004343 ]
4344 for protocol in protocols:
4345 ctx = ssl.SSLContext(protocol)
4346 self.assertEqual(ctx.post_handshake_auth, False)
4347
4348 ctx.post_handshake_auth = True
4349 self.assertEqual(ctx.post_handshake_auth, True)
4350
4351 ctx.verify_mode = ssl.CERT_REQUIRED
4352 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
4353 self.assertEqual(ctx.post_handshake_auth, True)
4354
4355 ctx.post_handshake_auth = False
4356 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
4357 self.assertEqual(ctx.post_handshake_auth, False)
4358
4359 ctx.verify_mode = ssl.CERT_OPTIONAL
4360 ctx.post_handshake_auth = True
4361 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
4362 self.assertEqual(ctx.post_handshake_auth, True)
4363
4364 def test_pha_required(self):
4365 client_context, server_context, hostname = testing_context()
4366 server_context.post_handshake_auth = True
4367 server_context.verify_mode = ssl.CERT_REQUIRED
4368 client_context.post_handshake_auth = True
4369 client_context.load_cert_chain(SIGNED_CERTFILE)
4370
4371 server = ThreadedEchoServer(context=server_context, chatty=False)
4372 with server:
4373 with client_context.wrap_socket(socket.socket(),
4374 server_hostname=hostname) as s:
4375 s.connect((HOST, server.port))
4376 s.write(b'HASCERT')
4377 self.assertEqual(s.recv(1024), b'FALSE\n')
4378 s.write(b'PHA')
4379 self.assertEqual(s.recv(1024), b'OK\n')
4380 s.write(b'HASCERT')
4381 self.assertEqual(s.recv(1024), b'TRUE\n')
4382 # PHA method just returns true when cert is already available
4383 s.write(b'PHA')
4384 self.assertEqual(s.recv(1024), b'OK\n')
4385 s.write(b'GETCERT')
4386 cert_text = s.recv(4096).decode('us-ascii')
4387 self.assertIn('Python Software Foundation CA', cert_text)
4388
4389 def test_pha_required_nocert(self):
4390 client_context, server_context, hostname = testing_context()
4391 server_context.post_handshake_auth = True
4392 server_context.verify_mode = ssl.CERT_REQUIRED
4393 client_context.post_handshake_auth = True
4394
Victor Stinner73ea5462019-07-09 14:33:49 +02004395 # Ignore expected SSLError in ConnectionHandler of ThreadedEchoServer
4396 # (it is only raised sometimes on Windows)
Hai Shie80697d2020-05-28 06:10:27 +08004397 with threading_helper.catch_threading_exception() as cm:
Victor Stinner73ea5462019-07-09 14:33:49 +02004398 server = ThreadedEchoServer(context=server_context, chatty=False)
4399 with server:
4400 with client_context.wrap_socket(socket.socket(),
4401 server_hostname=hostname) as s:
4402 s.connect((HOST, server.port))
4403 s.write(b'PHA')
4404 # receive CertificateRequest
4405 self.assertEqual(s.recv(1024), b'OK\n')
4406 # send empty Certificate + Finish
4407 s.write(b'HASCERT')
4408 # receive alert
4409 with self.assertRaisesRegex(
4410 ssl.SSLError,
4411 'tlsv13 alert certificate required'):
4412 s.recv(1024)
Christian Heimes9fb051f2018-09-23 08:32:31 +02004413
4414 def test_pha_optional(self):
4415 if support.verbose:
4416 sys.stdout.write("\n")
4417
4418 client_context, server_context, hostname = testing_context()
4419 server_context.post_handshake_auth = True
4420 server_context.verify_mode = ssl.CERT_REQUIRED
4421 client_context.post_handshake_auth = True
4422 client_context.load_cert_chain(SIGNED_CERTFILE)
4423
4424 # check CERT_OPTIONAL
4425 server_context.verify_mode = ssl.CERT_OPTIONAL
4426 server = ThreadedEchoServer(context=server_context, chatty=False)
4427 with server:
4428 with client_context.wrap_socket(socket.socket(),
4429 server_hostname=hostname) as s:
4430 s.connect((HOST, server.port))
4431 s.write(b'HASCERT')
4432 self.assertEqual(s.recv(1024), b'FALSE\n')
4433 s.write(b'PHA')
4434 self.assertEqual(s.recv(1024), b'OK\n')
4435 s.write(b'HASCERT')
4436 self.assertEqual(s.recv(1024), b'TRUE\n')
4437
4438 def test_pha_optional_nocert(self):
4439 if support.verbose:
4440 sys.stdout.write("\n")
4441
4442 client_context, server_context, hostname = testing_context()
4443 server_context.post_handshake_auth = True
4444 server_context.verify_mode = ssl.CERT_OPTIONAL
4445 client_context.post_handshake_auth = True
4446
4447 server = ThreadedEchoServer(context=server_context, chatty=False)
4448 with server:
4449 with client_context.wrap_socket(socket.socket(),
4450 server_hostname=hostname) as s:
4451 s.connect((HOST, server.port))
4452 s.write(b'HASCERT')
4453 self.assertEqual(s.recv(1024), b'FALSE\n')
4454 s.write(b'PHA')
4455 self.assertEqual(s.recv(1024), b'OK\n')
penguindustin96466302019-05-06 14:57:17 -04004456 # optional doesn't fail when client does not have a cert
Christian Heimes9fb051f2018-09-23 08:32:31 +02004457 s.write(b'HASCERT')
4458 self.assertEqual(s.recv(1024), b'FALSE\n')
4459
4460 def test_pha_no_pha_client(self):
4461 client_context, server_context, hostname = testing_context()
4462 server_context.post_handshake_auth = True
4463 server_context.verify_mode = ssl.CERT_REQUIRED
4464 client_context.load_cert_chain(SIGNED_CERTFILE)
4465
4466 server = ThreadedEchoServer(context=server_context, chatty=False)
4467 with server:
4468 with client_context.wrap_socket(socket.socket(),
4469 server_hostname=hostname) as s:
4470 s.connect((HOST, server.port))
4471 with self.assertRaisesRegex(ssl.SSLError, 'not server'):
4472 s.verify_client_post_handshake()
4473 s.write(b'PHA')
4474 self.assertIn(b'extension not received', s.recv(1024))
4475
4476 def test_pha_no_pha_server(self):
4477 # server doesn't have PHA enabled, cert is requested in handshake
4478 client_context, server_context, hostname = testing_context()
4479 server_context.verify_mode = ssl.CERT_REQUIRED
4480 client_context.post_handshake_auth = True
4481 client_context.load_cert_chain(SIGNED_CERTFILE)
4482
4483 server = ThreadedEchoServer(context=server_context, chatty=False)
4484 with server:
4485 with client_context.wrap_socket(socket.socket(),
4486 server_hostname=hostname) as s:
4487 s.connect((HOST, server.port))
4488 s.write(b'HASCERT')
4489 self.assertEqual(s.recv(1024), b'TRUE\n')
4490 # PHA doesn't fail if there is already a cert
4491 s.write(b'PHA')
4492 self.assertEqual(s.recv(1024), b'OK\n')
4493 s.write(b'HASCERT')
4494 self.assertEqual(s.recv(1024), b'TRUE\n')
4495
4496 def test_pha_not_tls13(self):
4497 # TLS 1.2
4498 client_context, server_context, hostname = testing_context()
4499 server_context.verify_mode = ssl.CERT_REQUIRED
4500 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
4501 client_context.post_handshake_auth = True
4502 client_context.load_cert_chain(SIGNED_CERTFILE)
4503
4504 server = ThreadedEchoServer(context=server_context, chatty=False)
4505 with server:
4506 with client_context.wrap_socket(socket.socket(),
4507 server_hostname=hostname) as s:
4508 s.connect((HOST, server.port))
4509 # PHA fails for TLS != 1.3
4510 s.write(b'PHA')
4511 self.assertIn(b'WRONG_SSL_VERSION', s.recv(1024))
4512
Christian Heimesf0f59302019-07-01 08:29:17 +02004513 def test_bpo37428_pha_cert_none(self):
4514 # verify that post_handshake_auth does not implicitly enable cert
4515 # validation.
4516 hostname = SIGNED_CERTFILE_HOSTNAME
4517 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4518 client_context.post_handshake_auth = True
4519 client_context.load_cert_chain(SIGNED_CERTFILE)
4520 # no cert validation and CA on client side
4521 client_context.check_hostname = False
4522 client_context.verify_mode = ssl.CERT_NONE
4523
4524 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
4525 server_context.load_cert_chain(SIGNED_CERTFILE)
4526 server_context.load_verify_locations(SIGNING_CA)
4527 server_context.post_handshake_auth = True
4528 server_context.verify_mode = ssl.CERT_REQUIRED
4529
4530 server = ThreadedEchoServer(context=server_context, chatty=False)
4531 with server:
4532 with client_context.wrap_socket(socket.socket(),
4533 server_hostname=hostname) as s:
4534 s.connect((HOST, server.port))
4535 s.write(b'HASCERT')
4536 self.assertEqual(s.recv(1024), b'FALSE\n')
4537 s.write(b'PHA')
4538 self.assertEqual(s.recv(1024), b'OK\n')
4539 s.write(b'HASCERT')
4540 self.assertEqual(s.recv(1024), b'TRUE\n')
4541 # server cert has not been validated
4542 self.assertEqual(s.getpeercert(), {})
4543
Christian Heimes9fb051f2018-09-23 08:32:31 +02004544
Christian Heimesc7f70692019-05-31 11:44:05 +02004545HAS_KEYLOG = hasattr(ssl.SSLContext, 'keylog_filename')
4546requires_keylog = unittest.skipUnless(
4547 HAS_KEYLOG, 'test requires OpenSSL 1.1.1 with keylog callback')
4548
4549class TestSSLDebug(unittest.TestCase):
4550
Hai Shia7f5d932020-08-04 00:41:24 +08004551 def keylog_lines(self, fname=os_helper.TESTFN):
Christian Heimesc7f70692019-05-31 11:44:05 +02004552 with open(fname) as f:
4553 return len(list(f))
4554
4555 @requires_keylog
Paul Monsonf3550692019-06-19 13:09:54 -07004556 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004557 def test_keylog_defaults(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004558 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004559 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4560 self.assertEqual(ctx.keylog_filename, None)
4561
Hai Shia7f5d932020-08-04 00:41:24 +08004562 self.assertFalse(os.path.isfile(os_helper.TESTFN))
4563 ctx.keylog_filename = os_helper.TESTFN
4564 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
4565 self.assertTrue(os.path.isfile(os_helper.TESTFN))
Christian Heimesc7f70692019-05-31 11:44:05 +02004566 self.assertEqual(self.keylog_lines(), 1)
4567
4568 ctx.keylog_filename = None
4569 self.assertEqual(ctx.keylog_filename, None)
4570
4571 with self.assertRaises((IsADirectoryError, PermissionError)):
4572 # Windows raises PermissionError
4573 ctx.keylog_filename = os.path.dirname(
Hai Shia7f5d932020-08-04 00:41:24 +08004574 os.path.abspath(os_helper.TESTFN))
Christian Heimesc7f70692019-05-31 11:44:05 +02004575
4576 with self.assertRaises(TypeError):
4577 ctx.keylog_filename = 1
4578
4579 @requires_keylog
Paul Monsonf3550692019-06-19 13:09:54 -07004580 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004581 def test_keylog_filename(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004582 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004583 client_context, server_context, hostname = testing_context()
4584
Hai Shia7f5d932020-08-04 00:41:24 +08004585 client_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004586 server = ThreadedEchoServer(context=server_context, chatty=False)
4587 with server:
4588 with client_context.wrap_socket(socket.socket(),
4589 server_hostname=hostname) as s:
4590 s.connect((HOST, server.port))
4591 # header, 5 lines for TLS 1.3
4592 self.assertEqual(self.keylog_lines(), 6)
4593
4594 client_context.keylog_filename = None
Hai Shia7f5d932020-08-04 00:41:24 +08004595 server_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004596 server = ThreadedEchoServer(context=server_context, chatty=False)
4597 with server:
4598 with client_context.wrap_socket(socket.socket(),
4599 server_hostname=hostname) as s:
4600 s.connect((HOST, server.port))
4601 self.assertGreaterEqual(self.keylog_lines(), 11)
4602
Hai Shia7f5d932020-08-04 00:41:24 +08004603 client_context.keylog_filename = os_helper.TESTFN
4604 server_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004605 server = ThreadedEchoServer(context=server_context, chatty=False)
4606 with server:
4607 with client_context.wrap_socket(socket.socket(),
4608 server_hostname=hostname) as s:
4609 s.connect((HOST, server.port))
4610 self.assertGreaterEqual(self.keylog_lines(), 21)
4611
4612 client_context.keylog_filename = None
4613 server_context.keylog_filename = None
4614
4615 @requires_keylog
4616 @unittest.skipIf(sys.flags.ignore_environment,
4617 "test is not compatible with ignore_environment")
Paul Monsonf3550692019-06-19 13:09:54 -07004618 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004619 def test_keylog_env(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004620 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004621 with unittest.mock.patch.dict(os.environ):
Hai Shia7f5d932020-08-04 00:41:24 +08004622 os.environ['SSLKEYLOGFILE'] = os_helper.TESTFN
4623 self.assertEqual(os.environ['SSLKEYLOGFILE'], os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004624
4625 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4626 self.assertEqual(ctx.keylog_filename, None)
4627
4628 ctx = ssl.create_default_context()
Hai Shia7f5d932020-08-04 00:41:24 +08004629 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004630
4631 ctx = ssl._create_stdlib_context()
Hai Shia7f5d932020-08-04 00:41:24 +08004632 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004633
4634 def test_msg_callback(self):
4635 client_context, server_context, hostname = testing_context()
4636
4637 def msg_cb(conn, direction, version, content_type, msg_type, data):
4638 pass
4639
4640 self.assertIs(client_context._msg_callback, None)
4641 client_context._msg_callback = msg_cb
4642 self.assertIs(client_context._msg_callback, msg_cb)
4643 with self.assertRaises(TypeError):
4644 client_context._msg_callback = object()
4645
4646 def test_msg_callback_tls12(self):
4647 client_context, server_context, hostname = testing_context()
4648 client_context.options |= ssl.OP_NO_TLSv1_3
4649
4650 msg = []
4651
4652 def msg_cb(conn, direction, version, content_type, msg_type, data):
4653 self.assertIsInstance(conn, ssl.SSLSocket)
4654 self.assertIsInstance(data, bytes)
4655 self.assertIn(direction, {'read', 'write'})
4656 msg.append((direction, version, content_type, msg_type))
4657
4658 client_context._msg_callback = msg_cb
4659
4660 server = ThreadedEchoServer(context=server_context, chatty=False)
4661 with server:
4662 with client_context.wrap_socket(socket.socket(),
4663 server_hostname=hostname) as s:
4664 s.connect((HOST, server.port))
4665
Christian Heimese35d1ba2019-06-03 20:40:15 +02004666 self.assertIn(
Christian Heimesc7f70692019-05-31 11:44:05 +02004667 ("read", TLSVersion.TLSv1_2, _TLSContentType.HANDSHAKE,
4668 _TLSMessageType.SERVER_KEY_EXCHANGE),
Christian Heimese35d1ba2019-06-03 20:40:15 +02004669 msg
4670 )
4671 self.assertIn(
Christian Heimesc7f70692019-05-31 11:44:05 +02004672 ("write", TLSVersion.TLSv1_2, _TLSContentType.CHANGE_CIPHER_SPEC,
4673 _TLSMessageType.CHANGE_CIPHER_SPEC),
Christian Heimese35d1ba2019-06-03 20:40:15 +02004674 msg
4675 )
Christian Heimesc7f70692019-05-31 11:44:05 +02004676
Christian Heimes77cde502021-03-21 16:13:09 +01004677 def test_msg_callback_deadlock_bpo43577(self):
4678 client_context, server_context, hostname = testing_context()
4679 server_context2 = testing_context()[1]
4680
4681 def msg_cb(conn, direction, version, content_type, msg_type, data):
4682 pass
4683
4684 def sni_cb(sock, servername, ctx):
4685 sock.context = server_context2
4686
4687 server_context._msg_callback = msg_cb
4688 server_context.sni_callback = sni_cb
4689
4690 server = ThreadedEchoServer(context=server_context, chatty=False)
4691 with server:
4692 with client_context.wrap_socket(socket.socket(),
4693 server_hostname=hostname) as s:
4694 s.connect((HOST, server.port))
4695 with client_context.wrap_socket(socket.socket(),
4696 server_hostname=hostname) as s:
4697 s.connect((HOST, server.port))
4698
Christian Heimesc7f70692019-05-31 11:44:05 +02004699
Thomas Woutersed03b412007-08-28 21:37:11 +00004700def test_main(verbose=False):
Antoine Pitrou15cee622010-08-04 16:45:21 +00004701 if support.verbose:
4702 plats = {
Antoine Pitrou15cee622010-08-04 16:45:21 +00004703 'Mac': platform.mac_ver,
4704 'Windows': platform.win32_ver,
4705 }
Petr Viktorin8b94b412018-05-16 11:51:18 -04004706 for name, func in plats.items():
4707 plat = func()
4708 if plat and plat[0]:
4709 plat = '%s %r' % (name, plat)
4710 break
4711 else:
4712 plat = repr(platform.platform())
Antoine Pitrou15cee622010-08-04 16:45:21 +00004713 print("test_ssl: testing with %r %r" %
4714 (ssl.OPENSSL_VERSION, ssl.OPENSSL_VERSION_INFO))
4715 print(" under %s" % plat)
Antoine Pitroud5323212010-10-22 18:19:07 +00004716 print(" HAS_SNI = %r" % ssl.HAS_SNI)
Antoine Pitrou609ef012013-03-29 18:09:06 +01004717 print(" OP_ALL = 0x%8x" % ssl.OP_ALL)
4718 try:
4719 print(" OP_NO_TLSv1_1 = 0x%8x" % ssl.OP_NO_TLSv1_1)
4720 except AttributeError:
4721 pass
Antoine Pitrou15cee622010-08-04 16:45:21 +00004722
Antoine Pitrou152efa22010-05-16 18:19:27 +00004723 for filename in [
Martin Panter3840b2a2016-03-27 01:53:46 +00004724 CERTFILE, BYTES_CERTFILE,
Antoine Pitrou152efa22010-05-16 18:19:27 +00004725 ONLYCERT, ONLYKEY, BYTES_ONLYCERT, BYTES_ONLYKEY,
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004726 SIGNED_CERTFILE, SIGNED_CERTFILE2, SIGNING_CA,
Antoine Pitrou152efa22010-05-16 18:19:27 +00004727 BADCERT, BADKEY, EMPTYCERT]:
4728 if not os.path.exists(filename):
4729 raise support.TestFailed("Can't read certificate file %r" % filename)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004730
Martin Panter3840b2a2016-03-27 01:53:46 +00004731 tests = [
4732 ContextTests, BasicSocketTests, SSLErrorTests, MemoryBIOTests,
Christian Heimes9d50ab52018-02-27 10:17:30 +01004733 SSLObjectTests, SimpleBackgroundTests, ThreadedTests,
Christian Heimesc7f70692019-05-31 11:44:05 +02004734 TestPostHandshakeAuth, TestSSLDebug
Martin Panter3840b2a2016-03-27 01:53:46 +00004735 ]
Thomas Woutersed03b412007-08-28 21:37:11 +00004736
Benjamin Petersonee8712c2008-05-20 21:35:26 +00004737 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00004738 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00004739
Hai Shie80697d2020-05-28 06:10:27 +08004740 thread_info = threading_helper.threading_setup()
Antoine Pitrou480a1242010-04-28 21:37:09 +00004741 try:
4742 support.run_unittest(*tests)
4743 finally:
Hai Shie80697d2020-05-28 06:10:27 +08004744 threading_helper.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00004745
4746if __name__ == "__main__":
4747 test_main()