blob: f4a84701c5d8b3d23c8efd6268b34503c1c98418 [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
Ethan Furmana02cb472021-04-21 10:20:44 -070015import datetime
Antoine Pitroucfcd8ad2010-04-23 23:31:47 +000016import gc
Thomas Woutersed03b412007-08-28 21:37:11 +000017import os
Antoine Pitroucfcd8ad2010-04-23 23:31:47 +000018import errno
Thomas Woutersed03b412007-08-28 21:37:11 +000019import pprint
Antoine Pitrou803e6d62010-10-13 10:36:15 +000020import urllib.request
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020021import threading
Thomas Woutersed03b412007-08-28 21:37:11 +000022import traceback
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
Miss Islington (bot)8bec9fb2021-06-24 16:38:01 -070032import warnings
33with warnings.catch_warnings():
34 warnings.simplefilter('ignore', DeprecationWarning)
35 import asyncore
36
Hai Shia7f5d932020-08-04 00:41:24 +080037ssl = import_helper.import_module("ssl")
Christian Heimes666991f2021-04-26 15:01:40 +020038import _ssl
Antoine Pitrou05d936d2010-10-13 11:38:36 +000039
Ethan Furmana02cb472021-04-21 10:20:44 -070040from ssl import TLSVersion, _TLSContentType, _TLSMessageType, _TLSAlertType
Martin Panter3840b2a2016-03-27 01:53:46 +000041
Paul Monsonf3550692019-06-19 13:09:54 -070042Py_DEBUG = hasattr(sys, 'gettotalrefcount')
43Py_DEBUG_WIN32 = Py_DEBUG and sys.platform == 'win32'
44
Antoine Pitrou2463e5f2013-03-28 22:24:43 +010045PROTOCOLS = sorted(ssl._PROTOCOL_NAMES)
Serhiy Storchaka16994912020-04-25 10:06:29 +030046HOST = socket_helper.HOST
Christian Heimesd37b74f2021-04-19 08:31:29 +020047IS_OPENSSL_3_0_0 = ssl.OPENSSL_VERSION_INFO >= (3, 0, 0)
Christian Heimes892d66e2018-01-29 14:10:18 +010048PY_SSL_DEFAULT_CIPHERS = sysconfig.get_config_var('PY_SSL_DEFAULT_CIPHERS')
Antoine Pitrou152efa22010-05-16 18:19:27 +000049
Victor Stinner3ef63442019-02-19 18:06:03 +010050PROTOCOL_TO_TLS_VERSION = {}
51for proto, ver in (
52 ("PROTOCOL_SSLv23", "SSLv3"),
53 ("PROTOCOL_TLSv1", "TLSv1"),
54 ("PROTOCOL_TLSv1_1", "TLSv1_1"),
55):
56 try:
57 proto = getattr(ssl, proto)
58 ver = getattr(ssl.TLSVersion, ver)
59 except AttributeError:
60 continue
61 PROTOCOL_TO_TLS_VERSION[proto] = ver
62
Christian Heimesefff7062013-11-21 03:35:02 +010063def data_file(*name):
64 return os.path.join(os.path.dirname(__file__), *name)
Antoine Pitrou152efa22010-05-16 18:19:27 +000065
Antoine Pitrou81564092010-10-08 23:06:24 +000066# The custom key and certificate files used in test_ssl are generated
67# using Lib/test/make_ssl_certs.py.
Miss Islington (bot)6fc1efa2021-07-26 15:34:32 -070068# Other certificates are simply fetched from the internet servers they
Antoine Pitrou81564092010-10-08 23:06:24 +000069# are meant to authenticate.
70
Antoine Pitrou152efa22010-05-16 18:19:27 +000071CERTFILE = data_file("keycert.pem")
Victor Stinner313a1202010-06-11 23:56:51 +000072BYTES_CERTFILE = os.fsencode(CERTFILE)
Antoine Pitrou152efa22010-05-16 18:19:27 +000073ONLYCERT = data_file("ssl_cert.pem")
74ONLYKEY = data_file("ssl_key.pem")
Victor Stinner313a1202010-06-11 23:56:51 +000075BYTES_ONLYCERT = os.fsencode(ONLYCERT)
76BYTES_ONLYKEY = os.fsencode(ONLYKEY)
Antoine Pitrou4fd1e6a2011-08-25 14:39:44 +020077CERTFILE_PROTECTED = data_file("keycert.passwd.pem")
78ONLYKEY_PROTECTED = data_file("ssl_key.passwd.pem")
79KEY_PASSWORD = "somepass"
Antoine Pitrou152efa22010-05-16 18:19:27 +000080CAPATH = data_file("capath")
Victor Stinner313a1202010-06-11 23:56:51 +000081BYTES_CAPATH = os.fsencode(CAPATH)
Christian Heimesefff7062013-11-21 03:35:02 +010082CAFILE_NEURONIO = data_file("capath", "4e1295a3.0")
83CAFILE_CACERT = data_file("capath", "5ed36f99.0")
84
Christian Heimesbd5c7d22018-01-20 15:16:30 +010085CERTFILE_INFO = {
86 'issuer': ((('countryName', 'XY'),),
87 (('localityName', 'Castle Anthrax'),),
88 (('organizationName', 'Python Software Foundation'),),
89 (('commonName', 'localhost'),)),
Christian Heimese6dac002018-08-30 07:25:49 +020090 'notAfter': 'Aug 26 14:23:15 2028 GMT',
91 'notBefore': 'Aug 29 14:23:15 2018 GMT',
92 'serialNumber': '98A7CF88C74A32ED',
Christian Heimesbd5c7d22018-01-20 15:16:30 +010093 'subject': ((('countryName', 'XY'),),
94 (('localityName', 'Castle Anthrax'),),
95 (('organizationName', 'Python Software Foundation'),),
96 (('commonName', 'localhost'),)),
97 'subjectAltName': (('DNS', 'localhost'),),
98 'version': 3
99}
Antoine Pitrou152efa22010-05-16 18:19:27 +0000100
Christian Heimes22587792013-11-21 23:56:13 +0100101# empty CRL
102CRLFILE = data_file("revocation.crl")
103
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100104# Two keys and certs signed by the same CA (for SNI tests)
105SIGNED_CERTFILE = data_file("keycert3.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +0200106SIGNED_CERTFILE_HOSTNAME = 'localhost'
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100107
108SIGNED_CERTFILE_INFO = {
109 'OCSP': ('http://testca.pythontest.net/testca/ocsp/',),
110 'caIssuers': ('http://testca.pythontest.net/testca/pycacert.cer',),
111 'crlDistributionPoints': ('http://testca.pythontest.net/testca/revocation.crl',),
112 'issuer': ((('countryName', 'XY'),),
113 (('organizationName', 'Python Software Foundation CA'),),
114 (('commonName', 'our-ca-server'),)),
Christian Heimesb467d9a2021-04-17 10:07:19 +0200115 'notAfter': 'Oct 28 14:23:16 2037 GMT',
Christian Heimese6dac002018-08-30 07:25:49 +0200116 'notBefore': 'Aug 29 14:23:16 2018 GMT',
117 'serialNumber': 'CB2D80995A69525C',
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100118 'subject': ((('countryName', 'XY'),),
119 (('localityName', 'Castle Anthrax'),),
120 (('organizationName', 'Python Software Foundation'),),
121 (('commonName', 'localhost'),)),
122 'subjectAltName': (('DNS', 'localhost'),),
123 'version': 3
124}
125
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100126SIGNED_CERTFILE2 = data_file("keycert4.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +0200127SIGNED_CERTFILE2_HOSTNAME = 'fakehostname'
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100128SIGNED_CERTFILE_ECC = data_file("keycertecc.pem")
129SIGNED_CERTFILE_ECC_HOSTNAME = 'localhost-ecc'
130
Martin Panter3840b2a2016-03-27 01:53:46 +0000131# Same certificate as pycacert.pem, but without extra text in file
132SIGNING_CA = data_file("capath", "ceff1710.0")
Christian Heimes1c03abd2016-09-06 23:25:35 +0200133# cert with all kinds of subject alt names
134ALLSANFILE = data_file("allsans.pem")
Christian Heimes66e57422018-01-29 14:25:13 +0100135IDNSANSFILE = data_file("idnsans.pem")
Christian Heimesb467d9a2021-04-17 10:07:19 +0200136NOSANFILE = data_file("nosan.pem")
137NOSAN_HOSTNAME = 'localhost'
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100138
Martin Panter3d81d932016-01-14 09:36:00 +0000139REMOTE_HOST = "self-signed.pythontest.net"
Antoine Pitrou152efa22010-05-16 18:19:27 +0000140
141EMPTYCERT = data_file("nullcert.pem")
142BADCERT = data_file("badcert.pem")
Martin Panter407b62f2016-01-30 03:41:43 +0000143NONEXISTINGCERT = data_file("XXXnonexisting.pem")
Antoine Pitrou152efa22010-05-16 18:19:27 +0000144BADKEY = data_file("badkey.pem")
Antoine Pitroud8c347a2011-10-01 19:20:25 +0200145NOKIACERT = data_file("nokia.pem")
Christian Heimes824f7f32013-08-17 00:54:47 +0200146NULLBYTECERT = data_file("nullbytecert.pem")
Christian Heimesa37f5242019-01-15 23:47:42 +0100147TALOS_INVALID_CRLDP = data_file("talos-2019-0758.pem")
Antoine Pitrou152efa22010-05-16 18:19:27 +0000148
Christian Heimes88bfd0b2018-08-14 12:54:19 +0200149DHFILE = data_file("ffdh3072.pem")
Antoine Pitrou0e576f12011-12-22 10:03:38 +0100150BYTES_DHFILE = os.fsencode(DHFILE)
Thomas Woutersed03b412007-08-28 21:37:11 +0000151
Christian Heimes358cfd42016-09-10 22:43:48 +0200152# Not defined in all versions of OpenSSL
153OP_NO_COMPRESSION = getattr(ssl, "OP_NO_COMPRESSION", 0)
154OP_SINGLE_DH_USE = getattr(ssl, "OP_SINGLE_DH_USE", 0)
155OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0)
156OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0)
Christian Heimes05d9fe32018-02-27 08:55:39 +0100157OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0)
Christian Heimes6f37ebc2021-04-09 17:59:21 +0200158OP_IGNORE_UNEXPECTED_EOF = getattr(ssl, "OP_IGNORE_UNEXPECTED_EOF", 0)
Christian Heimes358cfd42016-09-10 22:43:48 +0200159
Christian Heimesf6c6b582021-03-18 23:06:50 +0100160# Ubuntu has patched OpenSSL and changed behavior of security level 2
161# see https://bugs.python.org/issue41561#msg389003
162def is_ubuntu():
163 try:
164 # Assume that any references of "ubuntu" implies Ubuntu-like distro
165 # The workaround is not required for 18.04, but doesn't hurt either.
166 with open("/etc/os-release", encoding="utf-8") as f:
167 return "ubuntu" in f.read()
168 except FileNotFoundError:
169 return False
170
171if is_ubuntu():
172 def seclevel_workaround(*ctxs):
173 """"Lower security level to '1' and allow all ciphers for TLS 1.0/1"""
174 for ctx in ctxs:
Christian Heimes34477502021-04-12 12:00:38 +0200175 if (
176 hasattr(ctx, "minimum_version") and
177 ctx.minimum_version <= ssl.TLSVersion.TLSv1_1
178 ):
Christian Heimesf6c6b582021-03-18 23:06:50 +0100179 ctx.set_ciphers("@SECLEVEL=1:ALL")
180else:
181 def seclevel_workaround(*ctxs):
182 pass
183
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100184
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200185def has_tls_protocol(protocol):
186 """Check if a TLS protocol is available and enabled
187
188 :param protocol: enum ssl._SSLMethod member or name
189 :return: bool
190 """
191 if isinstance(protocol, str):
192 assert protocol.startswith('PROTOCOL_')
193 protocol = getattr(ssl, protocol, None)
194 if protocol is None:
195 return False
196 if protocol in {
197 ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS_SERVER,
198 ssl.PROTOCOL_TLS_CLIENT
199 }:
200 # auto-negotiate protocols are always available
201 return True
202 name = protocol.name
203 return has_tls_version(name[len('PROTOCOL_'):])
204
205
206@functools.lru_cache
207def has_tls_version(version):
208 """Check if a TLS/SSL version is enabled
209
210 :param version: TLS version name or ssl.TLSVersion member
211 :return: bool
212 """
213 if version == "SSLv2":
214 # never supported and not even in TLSVersion enum
215 return False
216
217 if isinstance(version, str):
218 version = ssl.TLSVersion.__members__[version]
219
220 # check compile time flags like ssl.HAS_TLSv1_2
221 if not getattr(ssl, f'HAS_{version.name}'):
222 return False
223
Christian Heimes5151d642021-04-09 15:43:06 +0200224 if IS_OPENSSL_3_0_0 and version < ssl.TLSVersion.TLSv1_2:
225 # bpo43791: 3.0.0-alpha14 fails with TLSV1_ALERT_INTERNAL_ERROR
226 return False
227
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200228 # check runtime and dynamic crypto policy settings. A TLS version may
229 # be compiled in but disabled by a policy or config option.
Christian Heimes2875c602021-04-19 07:27:10 +0200230 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200231 if (
Christian Heimes9f772682019-09-26 18:23:17 +0200232 hasattr(ctx, 'minimum_version') and
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200233 ctx.minimum_version != ssl.TLSVersion.MINIMUM_SUPPORTED and
234 version < ctx.minimum_version
235 ):
236 return False
237 if (
Christian Heimes9f772682019-09-26 18:23:17 +0200238 hasattr(ctx, 'maximum_version') and
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200239 ctx.maximum_version != ssl.TLSVersion.MAXIMUM_SUPPORTED and
240 version > ctx.maximum_version
241 ):
242 return False
243
244 return True
245
246
247def requires_tls_version(version):
248 """Decorator to skip tests when a required TLS version is not available
249
250 :param version: TLS version name or ssl.TLSVersion member
251 :return:
252 """
253 def decorator(func):
254 @functools.wraps(func)
255 def wrapper(*args, **kw):
256 if not has_tls_version(version):
257 raise unittest.SkipTest(f"{version} is not available.")
258 else:
259 return func(*args, **kw)
260 return wrapper
261 return decorator
262
263
Thomas Woutersed03b412007-08-28 21:37:11 +0000264def handle_error(prefix):
265 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000266 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000267 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +0000268
Christian Heimesb7b92252018-02-25 09:49:31 +0100269
Antoine Pitrouc695c952014-04-28 20:57:36 +0200270def utc_offset(): #NOTE: ignore issues like #1647654
271 # local time = utc time + utc offset
272 if time.daylight and time.localtime().tm_isdst > 0:
273 return -time.altzone # seconds
274 return -time.timezone
275
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100276
Christian Heimes2875c602021-04-19 07:27:10 +0200277ignore_deprecation = warnings_helper.ignore_warnings(
278 category=DeprecationWarning
279)
Antoine Pitrou23df4832010-08-04 17:14:06 +0000280
Christian Heimes2875c602021-04-19 07:27:10 +0200281
282def test_wrap_socket(sock, *,
Christian Heimesd0486372016-09-10 23:23:33 +0200283 cert_reqs=ssl.CERT_NONE, ca_certs=None,
284 ciphers=None, certfile=None, keyfile=None,
285 **kwargs):
Christian Heimes2875c602021-04-19 07:27:10 +0200286 if not kwargs.get("server_side"):
287 kwargs["server_hostname"] = SIGNED_CERTFILE_HOSTNAME
288 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
289 else:
290 context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimesd0486372016-09-10 23:23:33 +0200291 if cert_reqs is not None:
Christian Heimesa170fa12017-09-15 20:27:30 +0200292 if cert_reqs == ssl.CERT_NONE:
293 context.check_hostname = False
Christian Heimesd0486372016-09-10 23:23:33 +0200294 context.verify_mode = cert_reqs
295 if ca_certs is not None:
296 context.load_verify_locations(ca_certs)
297 if certfile is not None or keyfile is not None:
298 context.load_cert_chain(certfile, keyfile)
299 if ciphers is not None:
300 context.set_ciphers(ciphers)
301 return context.wrap_socket(sock, **kwargs)
302
Christian Heimesa170fa12017-09-15 20:27:30 +0200303
Christian Heimes666991f2021-04-26 15:01:40 +0200304def testing_context(server_cert=SIGNED_CERTFILE, *, server_chain=True):
Christian Heimesa170fa12017-09-15 20:27:30 +0200305 """Create context
306
307 client_context, server_context, hostname = testing_context()
308 """
309 if server_cert == SIGNED_CERTFILE:
310 hostname = SIGNED_CERTFILE_HOSTNAME
311 elif server_cert == SIGNED_CERTFILE2:
312 hostname = SIGNED_CERTFILE2_HOSTNAME
Christian Heimesb467d9a2021-04-17 10:07:19 +0200313 elif server_cert == NOSANFILE:
314 hostname = NOSAN_HOSTNAME
Christian Heimesa170fa12017-09-15 20:27:30 +0200315 else:
316 raise ValueError(server_cert)
317
318 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
319 client_context.load_verify_locations(SIGNING_CA)
320
321 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
322 server_context.load_cert_chain(server_cert)
Christian Heimes666991f2021-04-26 15:01:40 +0200323 if server_chain:
324 server_context.load_verify_locations(SIGNING_CA)
Christian Heimesa170fa12017-09-15 20:27:30 +0200325
326 return client_context, server_context, hostname
327
328
Antoine Pitrou152efa22010-05-16 18:19:27 +0000329class BasicSocketTests(unittest.TestCase):
Thomas Woutersed03b412007-08-28 21:37:11 +0000330
Antoine Pitrou480a1242010-04-28 21:37:09 +0000331 def test_constants(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000332 ssl.CERT_NONE
333 ssl.CERT_OPTIONAL
334 ssl.CERT_REQUIRED
Antoine Pitrou6db49442011-12-19 13:27:11 +0100335 ssl.OP_CIPHER_SERVER_PREFERENCE
Antoine Pitrou0e576f12011-12-22 10:03:38 +0100336 ssl.OP_SINGLE_DH_USE
Christian Heimesd37b74f2021-04-19 08:31:29 +0200337 ssl.OP_SINGLE_ECDH_USE
Christian Heimes39258d32021-04-17 11:36:35 +0200338 ssl.OP_NO_COMPRESSION
Christian Heimesd37b74f2021-04-19 08:31:29 +0200339 self.assertEqual(ssl.HAS_SNI, True)
340 self.assertEqual(ssl.HAS_ECDH, True)
341 self.assertEqual(ssl.HAS_TLSv1_2, True)
342 self.assertEqual(ssl.HAS_TLSv1_3, True)
Christian Heimescb5b68a2017-09-07 18:07:00 -0700343 ssl.OP_NO_SSLv2
344 ssl.OP_NO_SSLv3
345 ssl.OP_NO_TLSv1
346 ssl.OP_NO_TLSv1_3
Christian Heimes39258d32021-04-17 11:36:35 +0200347 ssl.OP_NO_TLSv1_1
348 ssl.OP_NO_TLSv1_2
Christian Heimesa170fa12017-09-15 20:27:30 +0200349 self.assertEqual(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv23)
Thomas Woutersed03b412007-08-28 21:37:11 +0000350
Christian Heimes91554e42021-05-02 09:47:45 +0200351 def test_ssl_types(self):
352 ssl_types = [
353 _ssl._SSLContext,
354 _ssl._SSLSocket,
355 _ssl.MemoryBIO,
356 _ssl.Certificate,
357 _ssl.SSLSession,
358 _ssl.SSLError,
359 ]
360 for ssl_type in ssl_types:
361 with self.subTest(ssl_type=ssl_type):
362 with self.assertRaisesRegex(TypeError, "immutable type"):
363 ssl_type.value = None
Erlend Egeberg Aasland0a3452e2021-06-24 01:46:25 +0200364 support.check_disallow_instantiation(self, _ssl.Certificate)
Christian Heimes91554e42021-05-02 09:47:45 +0200365
Christian Heimes9d50ab52018-02-27 10:17:30 +0100366 def test_private_init(self):
367 with self.assertRaisesRegex(TypeError, "public constructor"):
368 with socket.socket() as s:
369 ssl.SSLSocket(s)
370
Antoine Pitrou172f0252014-04-18 20:33:08 +0200371 def test_str_for_enums(self):
372 # Make sure that the PROTOCOL_* constants have enum-like string
373 # reprs.
Christian Heimes2875c602021-04-19 07:27:10 +0200374 proto = ssl.PROTOCOL_TLS_CLIENT
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700375 self.assertEqual(str(proto), '_SSLMethod.PROTOCOL_TLS_CLIENT')
Antoine Pitrou172f0252014-04-18 20:33:08 +0200376 ctx = ssl.SSLContext(proto)
377 self.assertIs(ctx.protocol, proto)
378
Antoine Pitrou480a1242010-04-28 21:37:09 +0000379 def test_random(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000380 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000381 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000382 sys.stdout.write("\n RAND_status is %d (%s)\n"
383 % (v, (v and "sufficient randomness") or
384 "insufficient randomness"))
Victor Stinner99c8b162011-05-24 12:05:19 +0200385
Christian Heimes2875c602021-04-19 07:27:10 +0200386 with warnings_helper.check_warnings():
387 data, is_cryptographic = ssl.RAND_pseudo_bytes(16)
Victor Stinner99c8b162011-05-24 12:05:19 +0200388 self.assertEqual(len(data), 16)
389 self.assertEqual(is_cryptographic, v == 1)
390 if v:
391 data = ssl.RAND_bytes(16)
392 self.assertEqual(len(data), 16)
Victor Stinner2e2baa92011-05-25 11:15:16 +0200393 else:
394 self.assertRaises(ssl.SSLError, ssl.RAND_bytes, 16)
Victor Stinner99c8b162011-05-24 12:05:19 +0200395
Victor Stinner1e81a392013-12-19 16:47:04 +0100396 # negative num is invalid
397 self.assertRaises(ValueError, ssl.RAND_bytes, -5)
Christian Heimes2875c602021-04-19 07:27:10 +0200398 with warnings_helper.check_warnings():
399 self.assertRaises(ValueError, ssl.RAND_pseudo_bytes, -5)
Victor Stinner1e81a392013-12-19 16:47:04 +0100400
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000401 ssl.RAND_add("this is a random string", 75.0)
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200402 ssl.RAND_add(b"this is a random bytes object", 75.0)
403 ssl.RAND_add(bytearray(b"this is a random bytearray object"), 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +0000404
Antoine Pitrou480a1242010-04-28 21:37:09 +0000405 def test_parse_cert(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000406 # note that this uses an 'unofficial' function in _ssl.c,
407 # provided solely for this test, to exercise the certificate
408 # parsing code
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100409 self.assertEqual(
410 ssl._ssl._test_decode_cert(CERTFILE),
411 CERTFILE_INFO
412 )
413 self.assertEqual(
414 ssl._ssl._test_decode_cert(SIGNED_CERTFILE),
415 SIGNED_CERTFILE_INFO
416 )
417
Antoine Pitroud8c347a2011-10-01 19:20:25 +0200418 # Issue #13034: the subjectAltName in some certificates
419 # (notably projects.developer.nokia.com:443) wasn't parsed
420 p = ssl._ssl._test_decode_cert(NOKIACERT)
421 if support.verbose:
422 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
423 self.assertEqual(p['subjectAltName'],
424 (('DNS', 'projects.developer.nokia.com'),
425 ('DNS', 'projects.forum.nokia.com'))
426 )
Christian Heimesbd3a7f92013-11-21 03:40:15 +0100427 # extra OCSP and AIA fields
428 self.assertEqual(p['OCSP'], ('http://ocsp.verisign.com',))
429 self.assertEqual(p['caIssuers'],
430 ('http://SVRIntl-G3-aia.verisign.com/SVRIntlG3.cer',))
431 self.assertEqual(p['crlDistributionPoints'],
432 ('http://SVRIntl-G3-crl.verisign.com/SVRIntlG3.crl',))
Thomas Woutersed03b412007-08-28 21:37:11 +0000433
Christian Heimesa37f5242019-01-15 23:47:42 +0100434 def test_parse_cert_CVE_2019_5010(self):
435 p = ssl._ssl._test_decode_cert(TALOS_INVALID_CRLDP)
436 if support.verbose:
437 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
438 self.assertEqual(
439 p,
440 {
441 'issuer': (
442 (('countryName', 'UK'),), (('commonName', 'cody-ca'),)),
443 'notAfter': 'Jun 14 18:00:58 2028 GMT',
444 'notBefore': 'Jun 18 18:00:58 2018 GMT',
445 'serialNumber': '02',
446 'subject': ((('countryName', 'UK'),),
447 (('commonName',
448 'codenomicon-vm-2.test.lal.cisco.com'),)),
449 'subjectAltName': (
450 ('DNS', 'codenomicon-vm-2.test.lal.cisco.com'),),
451 'version': 3
452 }
453 )
454
Christian Heimes824f7f32013-08-17 00:54:47 +0200455 def test_parse_cert_CVE_2013_4238(self):
456 p = ssl._ssl._test_decode_cert(NULLBYTECERT)
457 if support.verbose:
458 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
459 subject = ((('countryName', 'US'),),
460 (('stateOrProvinceName', 'Oregon'),),
461 (('localityName', 'Beaverton'),),
462 (('organizationName', 'Python Software Foundation'),),
463 (('organizationalUnitName', 'Python Core Development'),),
464 (('commonName', 'null.python.org\x00example.org'),),
465 (('emailAddress', 'python-dev@python.org'),))
466 self.assertEqual(p['subject'], subject)
467 self.assertEqual(p['issuer'], subject)
Christian Heimes157c9832013-08-25 14:12:41 +0200468 if ssl._OPENSSL_API_VERSION >= (0, 9, 8):
469 san = (('DNS', 'altnull.python.org\x00example.com'),
470 ('email', 'null@python.org\x00user@example.org'),
471 ('URI', 'http://null.python.org\x00http://example.org'),
472 ('IP Address', '192.0.2.1'),
Christian Heimes2b7de662019-12-07 17:59:36 +0100473 ('IP Address', '2001:DB8:0:0:0:0:0:1'))
Christian Heimes157c9832013-08-25 14:12:41 +0200474 else:
475 # OpenSSL 0.9.7 doesn't support IPv6 addresses in subjectAltName
476 san = (('DNS', 'altnull.python.org\x00example.com'),
477 ('email', 'null@python.org\x00user@example.org'),
478 ('URI', 'http://null.python.org\x00http://example.org'),
479 ('IP Address', '192.0.2.1'),
480 ('IP Address', '<invalid>'))
481
482 self.assertEqual(p['subjectAltName'], san)
Christian Heimes824f7f32013-08-17 00:54:47 +0200483
Christian Heimes1c03abd2016-09-06 23:25:35 +0200484 def test_parse_all_sans(self):
485 p = ssl._ssl._test_decode_cert(ALLSANFILE)
486 self.assertEqual(p['subjectAltName'],
487 (
488 ('DNS', 'allsans'),
489 ('othername', '<unsupported>'),
490 ('othername', '<unsupported>'),
491 ('email', 'user@example.org'),
492 ('DNS', 'www.example.org'),
493 ('DirName',
494 ((('countryName', 'XY'),),
495 (('localityName', 'Castle Anthrax'),),
496 (('organizationName', 'Python Software Foundation'),),
497 (('commonName', 'dirname example'),))),
498 ('URI', 'https://www.python.org/'),
499 ('IP Address', '127.0.0.1'),
Christian Heimes2b7de662019-12-07 17:59:36 +0100500 ('IP Address', '0:0:0:0:0:0:0:1'),
Christian Heimes1c03abd2016-09-06 23:25:35 +0200501 ('Registered ID', '1.2.3.4.5')
502 )
503 )
504
Antoine Pitrou480a1242010-04-28 21:37:09 +0000505 def test_DER_to_PEM(self):
Martin Panter3d81d932016-01-14 09:36:00 +0000506 with open(CAFILE_CACERT, 'r') as f:
Antoine Pitrou480a1242010-04-28 21:37:09 +0000507 pem = f.read()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000508 d1 = ssl.PEM_cert_to_DER_cert(pem)
509 p2 = ssl.DER_cert_to_PEM_cert(d1)
510 d2 = ssl.PEM_cert_to_DER_cert(p2)
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000511 self.assertEqual(d1, d2)
Antoine Pitrou9bfbe612010-04-27 22:08:08 +0000512 if not p2.startswith(ssl.PEM_HEADER + '\n'):
513 self.fail("DER-to-PEM didn't include correct header:\n%r\n" % p2)
514 if not p2.endswith('\n' + ssl.PEM_FOOTER + '\n'):
515 self.fail("DER-to-PEM didn't include correct footer:\n%r\n" % p2)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000516
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000517 def test_openssl_version(self):
518 n = ssl.OPENSSL_VERSION_NUMBER
519 t = ssl.OPENSSL_VERSION_INFO
520 s = ssl.OPENSSL_VERSION
521 self.assertIsInstance(n, int)
522 self.assertIsInstance(t, tuple)
523 self.assertIsInstance(s, str)
524 # Some sanity checks follow
Christian Heimesd37b74f2021-04-19 08:31:29 +0200525 # >= 1.1.1
526 self.assertGreaterEqual(n, 0x10101000)
Christian Heimes2b7de662019-12-07 17:59:36 +0100527 # < 4.0
528 self.assertLess(n, 0x40000000)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000529 major, minor, fix, patch, status = t
Christian Heimes2b7de662019-12-07 17:59:36 +0100530 self.assertGreaterEqual(major, 1)
531 self.assertLess(major, 4)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000532 self.assertGreaterEqual(minor, 0)
533 self.assertLess(minor, 256)
534 self.assertGreaterEqual(fix, 0)
535 self.assertLess(fix, 256)
536 self.assertGreaterEqual(patch, 0)
Ned Deily05784a72015-02-05 17:20:13 +1100537 self.assertLessEqual(patch, 63)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000538 self.assertGreaterEqual(status, 0)
539 self.assertLessEqual(status, 15)
Christian Heimesd37b74f2021-04-19 08:31:29 +0200540
541 libressl_ver = f"LibreSSL {major:d}"
542 openssl_ver = f"OpenSSL {major:d}.{minor:d}.{fix:d}"
543 self.assertTrue(
544 s.startswith((openssl_ver, libressl_ver)),
545 (s, t, hex(n))
546 )
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000547
Antoine Pitrou9d543662010-04-23 23:10:32 +0000548 @support.cpython_only
549 def test_refcycle(self):
550 # Issue #7943: an SSL object doesn't create reference cycles with
551 # itself.
552 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200553 ss = test_wrap_socket(s)
Antoine Pitrou9d543662010-04-23 23:10:32 +0000554 wr = weakref.ref(ss)
Hai Shia7f5d932020-08-04 00:41:24 +0800555 with warnings_helper.check_warnings(("", ResourceWarning)):
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100556 del ss
Victor Stinnere0b75b72016-03-21 17:26:04 +0100557 self.assertEqual(wr(), None)
Antoine Pitrou9d543662010-04-23 23:10:32 +0000558
Antoine Pitroua468adc2010-09-14 14:43:44 +0000559 def test_wrapped_unconnected(self):
560 # Methods on an unconnected SSLSocket propagate the original
Andrew Svetlov0832af62012-12-18 23:10:48 +0200561 # OSError raise by the underlying socket object.
Antoine Pitroua468adc2010-09-14 14:43:44 +0000562 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200563 with test_wrap_socket(s) as ss:
Antoine Pitroue9bb4732013-01-12 21:56:56 +0100564 self.assertRaises(OSError, ss.recv, 1)
565 self.assertRaises(OSError, ss.recv_into, bytearray(b'x'))
566 self.assertRaises(OSError, ss.recvfrom, 1)
567 self.assertRaises(OSError, ss.recvfrom_into, bytearray(b'x'), 1)
568 self.assertRaises(OSError, ss.send, b'x')
569 self.assertRaises(OSError, ss.sendto, b'x', ('0.0.0.0', 0))
Serhiy Storchaka42b1d612018-12-06 22:36:55 +0200570 self.assertRaises(NotImplementedError, ss.dup)
Christian Heimes141c5e82018-02-24 21:10:57 +0100571 self.assertRaises(NotImplementedError, ss.sendmsg,
572 [b'x'], (), 0, ('0.0.0.0', 0))
Serhiy Storchaka42b1d612018-12-06 22:36:55 +0200573 self.assertRaises(NotImplementedError, ss.recvmsg, 100)
574 self.assertRaises(NotImplementedError, ss.recvmsg_into,
575 [bytearray(100)])
Antoine Pitroua468adc2010-09-14 14:43:44 +0000576
Antoine Pitrou40f08742010-04-24 22:04:40 +0000577 def test_timeout(self):
578 # Issue #8524: when creating an SSL socket, the timeout of the
579 # original socket should be retained.
580 for timeout in (None, 0.0, 5.0):
581 s = socket.socket(socket.AF_INET)
582 s.settimeout(timeout)
Christian Heimesd0486372016-09-10 23:23:33 +0200583 with test_wrap_socket(s) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100584 self.assertEqual(timeout, ss.gettimeout())
Antoine Pitrou40f08742010-04-24 22:04:40 +0000585
Miss Islington (bot)4becc562021-06-13 05:07:00 -0700586 def test_openssl111_deprecations(self):
587 options = [
588 ssl.OP_NO_TLSv1,
589 ssl.OP_NO_TLSv1_1,
590 ssl.OP_NO_TLSv1_2,
591 ssl.OP_NO_TLSv1_3
592 ]
593 protocols = [
594 ssl.PROTOCOL_TLSv1,
595 ssl.PROTOCOL_TLSv1_1,
596 ssl.PROTOCOL_TLSv1_2,
597 ssl.PROTOCOL_TLS
598 ]
599 versions = [
600 ssl.TLSVersion.SSLv3,
601 ssl.TLSVersion.TLSv1,
602 ssl.TLSVersion.TLSv1_1,
603 ]
604
605 for option in options:
606 with self.subTest(option=option):
607 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
608 with self.assertWarns(DeprecationWarning) as cm:
609 ctx.options |= option
610 self.assertEqual(
Miss Islington (bot)08f2b9d2021-06-17 03:00:56 -0700611 'ssl.OP_NO_SSL*/ssl.OP_NO_TLS* options are deprecated',
Miss Islington (bot)4becc562021-06-13 05:07:00 -0700612 str(cm.warning)
613 )
614
615 for protocol in protocols:
616 with self.subTest(protocol=protocol):
617 with self.assertWarns(DeprecationWarning) as cm:
618 ssl.SSLContext(protocol)
619 self.assertEqual(
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700620 f'ssl.{protocol.name} is deprecated',
Miss Islington (bot)4becc562021-06-13 05:07:00 -0700621 str(cm.warning)
622 )
623
624 for version in versions:
625 with self.subTest(version=version):
626 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
627 with self.assertWarns(DeprecationWarning) as cm:
628 ctx.minimum_version = version
629 self.assertEqual(
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700630 f'ssl.{version!s} is deprecated',
Miss Islington (bot)4becc562021-06-13 05:07:00 -0700631 str(cm.warning)
632 )
633
Christian Heimes2875c602021-04-19 07:27:10 +0200634 @ignore_deprecation
Christian Heimesd0486372016-09-10 23:23:33 +0200635 def test_errors_sslwrap(self):
Giampaolo Rodolà745ab382010-08-29 19:25:49 +0000636 sock = socket.socket()
Ezio Melottied3a7d22010-12-01 02:32:32 +0000637 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000638 "certfile must be specified",
639 ssl.wrap_socket, sock, keyfile=CERTFILE)
Ezio Melottied3a7d22010-12-01 02:32:32 +0000640 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000641 "certfile must be specified for server-side operations",
642 ssl.wrap_socket, sock, server_side=True)
Ezio Melottied3a7d22010-12-01 02:32:32 +0000643 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000644 "certfile must be specified for server-side operations",
Christian Heimesd0486372016-09-10 23:23:33 +0200645 ssl.wrap_socket, sock, server_side=True, certfile="")
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100646 with ssl.wrap_socket(sock, server_side=True, certfile=CERTFILE) as s:
647 self.assertRaisesRegex(ValueError, "can't connect in server-side mode",
Christian Heimesd0486372016-09-10 23:23:33 +0200648 s.connect, (HOST, 8080))
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200649 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000650 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000651 ssl.wrap_socket(sock, certfile=NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +0000652 self.assertEqual(cm.exception.errno, errno.ENOENT)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200653 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000654 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000655 ssl.wrap_socket(sock,
656 certfile=CERTFILE, keyfile=NONEXISTINGCERT)
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000657 self.assertEqual(cm.exception.errno, errno.ENOENT)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200658 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000659 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000660 ssl.wrap_socket(sock,
661 certfile=NONEXISTINGCERT, keyfile=NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +0000662 self.assertEqual(cm.exception.errno, errno.ENOENT)
Giampaolo Rodolà745ab382010-08-29 19:25:49 +0000663
Martin Panter3464ea22016-02-01 21:58:11 +0000664 def bad_cert_test(self, certfile):
665 """Check that trying to use the given client certificate fails"""
666 certfile = os.path.join(os.path.dirname(__file__) or os.curdir,
667 certfile)
668 sock = socket.socket()
669 self.addCleanup(sock.close)
670 with self.assertRaises(ssl.SSLError):
Christian Heimesd0486372016-09-10 23:23:33 +0200671 test_wrap_socket(sock,
Christian Heimesa170fa12017-09-15 20:27:30 +0200672 certfile=certfile)
Martin Panter3464ea22016-02-01 21:58:11 +0000673
674 def test_empty_cert(self):
675 """Wrapping with an empty cert file"""
676 self.bad_cert_test("nullcert.pem")
677
678 def test_malformed_cert(self):
679 """Wrapping with a badly formatted certificate (syntax error)"""
680 self.bad_cert_test("badcert.pem")
681
682 def test_malformed_key(self):
683 """Wrapping with a badly formatted key (syntax error)"""
684 self.bad_cert_test("badkey.pem")
685
Christian Heimes2875c602021-04-19 07:27:10 +0200686 @ignore_deprecation
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000687 def test_match_hostname(self):
688 def ok(cert, hostname):
689 ssl.match_hostname(cert, hostname)
690 def fail(cert, hostname):
691 self.assertRaises(ssl.CertificateError,
692 ssl.match_hostname, cert, hostname)
693
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100694 # -- Hostname matching --
695
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000696 cert = {'subject': ((('commonName', 'example.com'),),)}
697 ok(cert, 'example.com')
698 ok(cert, 'ExAmple.cOm')
699 fail(cert, 'www.example.com')
700 fail(cert, '.example.com')
701 fail(cert, 'example.org')
702 fail(cert, 'exampleXcom')
703
704 cert = {'subject': ((('commonName', '*.a.com'),),)}
705 ok(cert, 'foo.a.com')
706 fail(cert, 'bar.foo.a.com')
707 fail(cert, 'a.com')
708 fail(cert, 'Xa.com')
709 fail(cert, '.a.com')
710
Mandeep Singhede2ac92017-11-27 04:01:27 +0530711 # only match wildcards when they are the only thing
712 # in left-most segment
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000713 cert = {'subject': ((('commonName', 'f*.com'),),)}
Mandeep Singhede2ac92017-11-27 04:01:27 +0530714 fail(cert, 'foo.com')
715 fail(cert, 'f.com')
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000716 fail(cert, 'bar.com')
717 fail(cert, 'foo.a.com')
718 fail(cert, 'bar.foo.com')
719
Christian Heimes824f7f32013-08-17 00:54:47 +0200720 # NULL bytes are bad, CVE-2013-4073
721 cert = {'subject': ((('commonName',
722 'null.python.org\x00example.org'),),)}
723 ok(cert, 'null.python.org\x00example.org') # or raise an error?
724 fail(cert, 'example.org')
725 fail(cert, 'null.python.org')
726
Georg Brandl72c98d32013-10-27 07:16:53 +0100727 # error cases with wildcards
728 cert = {'subject': ((('commonName', '*.*.a.com'),),)}
729 fail(cert, 'bar.foo.a.com')
730 fail(cert, 'a.com')
731 fail(cert, 'Xa.com')
732 fail(cert, '.a.com')
733
734 cert = {'subject': ((('commonName', 'a.*.com'),),)}
735 fail(cert, 'a.foo.com')
736 fail(cert, 'a..com')
737 fail(cert, 'a.com')
738
739 # wildcard doesn't match IDNA prefix 'xn--'
740 idna = 'püthon.python.org'.encode("idna").decode("ascii")
741 cert = {'subject': ((('commonName', idna),),)}
742 ok(cert, idna)
743 cert = {'subject': ((('commonName', 'x*.python.org'),),)}
744 fail(cert, idna)
745 cert = {'subject': ((('commonName', 'xn--p*.python.org'),),)}
746 fail(cert, idna)
747
748 # wildcard in first fragment and IDNA A-labels in sequent fragments
749 # are supported.
750 idna = 'www*.pythön.org'.encode("idna").decode("ascii")
751 cert = {'subject': ((('commonName', idna),),)}
Mandeep Singhede2ac92017-11-27 04:01:27 +0530752 fail(cert, 'www.pythön.org'.encode("idna").decode("ascii"))
753 fail(cert, 'www1.pythön.org'.encode("idna").decode("ascii"))
Georg Brandl72c98d32013-10-27 07:16:53 +0100754 fail(cert, 'ftp.pythön.org'.encode("idna").decode("ascii"))
755 fail(cert, 'pythön.org'.encode("idna").decode("ascii"))
756
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000757 # Slightly fake real-world example
758 cert = {'notAfter': 'Jun 26 21:41:46 2011 GMT',
759 'subject': ((('commonName', 'linuxfrz.org'),),),
760 'subjectAltName': (('DNS', 'linuxfr.org'),
761 ('DNS', 'linuxfr.com'),
762 ('othername', '<unsupported>'))}
763 ok(cert, 'linuxfr.org')
764 ok(cert, 'linuxfr.com')
765 # Not a "DNS" entry
766 fail(cert, '<unsupported>')
767 # When there is a subjectAltName, commonName isn't used
768 fail(cert, 'linuxfrz.org')
769
770 # A pristine real-world example
771 cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT',
772 'subject': ((('countryName', 'US'),),
773 (('stateOrProvinceName', 'California'),),
774 (('localityName', 'Mountain View'),),
775 (('organizationName', 'Google Inc'),),
776 (('commonName', 'mail.google.com'),))}
777 ok(cert, 'mail.google.com')
778 fail(cert, 'gmail.com')
779 # Only commonName is considered
780 fail(cert, 'California')
781
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100782 # -- IPv4 matching --
783 cert = {'subject': ((('commonName', 'example.com'),),),
784 'subjectAltName': (('DNS', 'example.com'),
785 ('IP Address', '10.11.12.13'),
Christian Heimes477b1b22019-07-02 20:39:42 +0200786 ('IP Address', '14.15.16.17'),
787 ('IP Address', '127.0.0.1'))}
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100788 ok(cert, '10.11.12.13')
789 ok(cert, '14.15.16.17')
Christian Heimes477b1b22019-07-02 20:39:42 +0200790 # socket.inet_ntoa(socket.inet_aton('127.1')) == '127.0.0.1'
791 fail(cert, '127.1')
792 fail(cert, '14.15.16.17 ')
793 fail(cert, '14.15.16.17 extra data')
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100794 fail(cert, '14.15.16.18')
795 fail(cert, 'example.net')
796
797 # -- IPv6 matching --
Serhiy Storchaka16994912020-04-25 10:06:29 +0300798 if socket_helper.IPV6_ENABLED:
Christian Heimesaef12832018-02-24 14:35:56 +0100799 cert = {'subject': ((('commonName', 'example.com'),),),
800 'subjectAltName': (
801 ('DNS', 'example.com'),
802 ('IP Address', '2001:0:0:0:0:0:0:CAFE\n'),
803 ('IP Address', '2003:0:0:0:0:0:0:BABA\n'))}
804 ok(cert, '2001::cafe')
805 ok(cert, '2003::baba')
Christian Heimes477b1b22019-07-02 20:39:42 +0200806 fail(cert, '2003::baba ')
807 fail(cert, '2003::baba extra data')
Christian Heimesaef12832018-02-24 14:35:56 +0100808 fail(cert, '2003::bebe')
809 fail(cert, 'example.net')
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100810
811 # -- Miscellaneous --
812
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000813 # Neither commonName nor subjectAltName
814 cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT',
815 'subject': ((('countryName', 'US'),),
816 (('stateOrProvinceName', 'California'),),
817 (('localityName', 'Mountain View'),),
818 (('organizationName', 'Google Inc'),))}
819 fail(cert, 'mail.google.com')
820
Antoine Pitrou1c86b442011-05-06 15:19:49 +0200821 # No DNS entry in subjectAltName but a commonName
822 cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT',
823 'subject': ((('countryName', 'US'),),
824 (('stateOrProvinceName', 'California'),),
825 (('localityName', 'Mountain View'),),
826 (('commonName', 'mail.google.com'),)),
827 'subjectAltName': (('othername', 'blabla'), )}
828 ok(cert, 'mail.google.com')
829
830 # No DNS entry subjectAltName and no commonName
831 cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT',
832 'subject': ((('countryName', 'US'),),
833 (('stateOrProvinceName', 'California'),),
834 (('localityName', 'Mountain View'),),
835 (('organizationName', 'Google Inc'),)),
836 'subjectAltName': (('othername', 'blabla'),)}
837 fail(cert, 'google.com')
838
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000839 # Empty cert / no cert
840 self.assertRaises(ValueError, ssl.match_hostname, None, 'example.com')
841 self.assertRaises(ValueError, ssl.match_hostname, {}, 'example.com')
842
Antoine Pitrou636f93c2013-05-18 17:56:42 +0200843 # Issue #17980: avoid denials of service by refusing more than one
844 # wildcard per fragment.
Christian Heimesaef12832018-02-24 14:35:56 +0100845 cert = {'subject': ((('commonName', 'a*b.example.com'),),)}
846 with self.assertRaisesRegex(
847 ssl.CertificateError,
848 "partial wildcards in leftmost label are not supported"):
849 ssl.match_hostname(cert, 'axxb.example.com')
850
851 cert = {'subject': ((('commonName', 'www.*.example.com'),),)}
852 with self.assertRaisesRegex(
853 ssl.CertificateError,
854 "wildcard can only be present in the leftmost label"):
855 ssl.match_hostname(cert, 'www.sub.example.com')
856
857 cert = {'subject': ((('commonName', 'a*b*.example.com'),),)}
858 with self.assertRaisesRegex(
859 ssl.CertificateError,
860 "too many wildcards"):
861 ssl.match_hostname(cert, 'axxbxxc.example.com')
862
863 cert = {'subject': ((('commonName', '*'),),)}
864 with self.assertRaisesRegex(
865 ssl.CertificateError,
866 "sole wildcard without additional labels are not support"):
867 ssl.match_hostname(cert, 'host')
868
869 cert = {'subject': ((('commonName', '*.com'),),)}
870 with self.assertRaisesRegex(
871 ssl.CertificateError,
872 r"hostname 'com' doesn't match '\*.com'"):
873 ssl.match_hostname(cert, 'com')
874
875 # extra checks for _inet_paton()
876 for invalid in ['1', '', '1.2.3', '256.0.0.1', '127.0.0.1/24']:
877 with self.assertRaises(ValueError):
878 ssl._inet_paton(invalid)
879 for ipaddr in ['127.0.0.1', '192.168.0.1']:
880 self.assertTrue(ssl._inet_paton(ipaddr))
Serhiy Storchaka16994912020-04-25 10:06:29 +0300881 if socket_helper.IPV6_ENABLED:
Christian Heimesaef12832018-02-24 14:35:56 +0100882 for ipaddr in ['::1', '2001:db8:85a3::8a2e:370:7334']:
883 self.assertTrue(ssl._inet_paton(ipaddr))
Antoine Pitrou636f93c2013-05-18 17:56:42 +0200884
Antoine Pitroud5323212010-10-22 18:19:07 +0000885 def test_server_side(self):
886 # server_hostname doesn't work for server sockets
Christian Heimesa170fa12017-09-15 20:27:30 +0200887 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroud2eca372010-10-29 23:41:37 +0000888 with socket.socket() as sock:
889 self.assertRaises(ValueError, ctx.wrap_socket, sock, True,
890 server_hostname="some.hostname")
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000891
Antoine Pitroud6494802011-07-21 01:11:30 +0200892 def test_unknown_channel_binding(self):
893 # should raise ValueError for unknown type
Giampaolo Rodolaeb7e29f2019-04-09 00:34:02 +0200894 s = socket.create_server(('127.0.0.1', 0))
Antoine Pitroub1fdf472014-10-05 20:41:53 +0200895 c = socket.socket(socket.AF_INET)
896 c.connect(s.getsockname())
Christian Heimesd0486372016-09-10 23:23:33 +0200897 with test_wrap_socket(c, do_handshake_on_connect=False) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100898 with self.assertRaises(ValueError):
899 ss.get_channel_binding("unknown-type")
Antoine Pitroub1fdf472014-10-05 20:41:53 +0200900 s.close()
Antoine Pitroud6494802011-07-21 01:11:30 +0200901
902 @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES,
903 "'tls-unique' channel binding not available")
904 def test_tls_unique_channel_binding(self):
905 # unconnected should return None for known type
906 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200907 with test_wrap_socket(s) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100908 self.assertIsNone(ss.get_channel_binding("tls-unique"))
Antoine Pitroud6494802011-07-21 01:11:30 +0200909 # the same for server-side
910 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200911 with test_wrap_socket(s, server_side=True, certfile=CERTFILE) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100912 self.assertIsNone(ss.get_channel_binding("tls-unique"))
Antoine Pitroud6494802011-07-21 01:11:30 +0200913
Benjamin Peterson36f7b972013-01-10 14:16:20 -0600914 def test_dealloc_warn(self):
Christian Heimesd0486372016-09-10 23:23:33 +0200915 ss = test_wrap_socket(socket.socket(socket.AF_INET))
Benjamin Peterson36f7b972013-01-10 14:16:20 -0600916 r = repr(ss)
917 with self.assertWarns(ResourceWarning) as cm:
918 ss = None
919 support.gc_collect()
920 self.assertIn(r, str(cm.warning.args[0]))
921
Christian Heimes6d7ad132013-06-09 18:02:55 +0200922 def test_get_default_verify_paths(self):
923 paths = ssl.get_default_verify_paths()
924 self.assertEqual(len(paths), 6)
925 self.assertIsInstance(paths, ssl.DefaultVerifyPaths)
926
Hai Shia7f5d932020-08-04 00:41:24 +0800927 with os_helper.EnvironmentVarGuard() as env:
Christian Heimes6d7ad132013-06-09 18:02:55 +0200928 env["SSL_CERT_DIR"] = CAPATH
929 env["SSL_CERT_FILE"] = CERTFILE
930 paths = ssl.get_default_verify_paths()
931 self.assertEqual(paths.cafile, CERTFILE)
932 self.assertEqual(paths.capath, CAPATH)
933
Christian Heimes44109d72013-11-22 01:51:30 +0100934 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
935 def test_enum_certificates(self):
936 self.assertTrue(ssl.enum_certificates("CA"))
937 self.assertTrue(ssl.enum_certificates("ROOT"))
938
939 self.assertRaises(TypeError, ssl.enum_certificates)
940 self.assertRaises(WindowsError, ssl.enum_certificates, "")
941
Christian Heimesc2d65e12013-11-22 16:13:55 +0100942 trust_oids = set()
943 for storename in ("CA", "ROOT"):
944 store = ssl.enum_certificates(storename)
945 self.assertIsInstance(store, list)
946 for element in store:
947 self.assertIsInstance(element, tuple)
948 self.assertEqual(len(element), 3)
949 cert, enc, trust = element
950 self.assertIsInstance(cert, bytes)
951 self.assertIn(enc, {"x509_asn", "pkcs_7_asn"})
Christian Heimes915cd3f2019-09-09 18:06:55 +0200952 self.assertIsInstance(trust, (frozenset, set, bool))
953 if isinstance(trust, (frozenset, set)):
Christian Heimesc2d65e12013-11-22 16:13:55 +0100954 trust_oids.update(trust)
Christian Heimes44109d72013-11-22 01:51:30 +0100955
956 serverAuth = "1.3.6.1.5.5.7.3.1"
Christian Heimesc2d65e12013-11-22 16:13:55 +0100957 self.assertIn(serverAuth, trust_oids)
Christian Heimes6d7ad132013-06-09 18:02:55 +0200958
Christian Heimes46bebee2013-06-09 19:03:31 +0200959 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
Christian Heimes44109d72013-11-22 01:51:30 +0100960 def test_enum_crls(self):
961 self.assertTrue(ssl.enum_crls("CA"))
962 self.assertRaises(TypeError, ssl.enum_crls)
963 self.assertRaises(WindowsError, ssl.enum_crls, "")
Christian Heimes46bebee2013-06-09 19:03:31 +0200964
Christian Heimes44109d72013-11-22 01:51:30 +0100965 crls = ssl.enum_crls("CA")
966 self.assertIsInstance(crls, list)
967 for element in crls:
968 self.assertIsInstance(element, tuple)
969 self.assertEqual(len(element), 2)
970 self.assertIsInstance(element[0], bytes)
971 self.assertIn(element[1], {"x509_asn", "pkcs_7_asn"})
Christian Heimes46bebee2013-06-09 19:03:31 +0200972
Christian Heimes46bebee2013-06-09 19:03:31 +0200973
Christian Heimesa6bc95a2013-11-17 19:59:14 +0100974 def test_asn1object(self):
975 expected = (129, 'serverAuth', 'TLS Web Server Authentication',
976 '1.3.6.1.5.5.7.3.1')
977
978 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1')
979 self.assertEqual(val, expected)
980 self.assertEqual(val.nid, 129)
981 self.assertEqual(val.shortname, 'serverAuth')
982 self.assertEqual(val.longname, 'TLS Web Server Authentication')
983 self.assertEqual(val.oid, '1.3.6.1.5.5.7.3.1')
984 self.assertIsInstance(val, ssl._ASN1Object)
985 self.assertRaises(ValueError, ssl._ASN1Object, 'serverAuth')
986
987 val = ssl._ASN1Object.fromnid(129)
988 self.assertEqual(val, expected)
989 self.assertIsInstance(val, ssl._ASN1Object)
990 self.assertRaises(ValueError, ssl._ASN1Object.fromnid, -1)
Christian Heimes5398e1a2013-11-22 16:20:53 +0100991 with self.assertRaisesRegex(ValueError, "unknown NID 100000"):
992 ssl._ASN1Object.fromnid(100000)
Christian Heimesa6bc95a2013-11-17 19:59:14 +0100993 for i in range(1000):
994 try:
995 obj = ssl._ASN1Object.fromnid(i)
996 except ValueError:
997 pass
998 else:
999 self.assertIsInstance(obj.nid, int)
1000 self.assertIsInstance(obj.shortname, str)
1001 self.assertIsInstance(obj.longname, str)
1002 self.assertIsInstance(obj.oid, (str, type(None)))
1003
1004 val = ssl._ASN1Object.fromname('TLS Web Server Authentication')
1005 self.assertEqual(val, expected)
1006 self.assertIsInstance(val, ssl._ASN1Object)
1007 self.assertEqual(ssl._ASN1Object.fromname('serverAuth'), expected)
1008 self.assertEqual(ssl._ASN1Object.fromname('1.3.6.1.5.5.7.3.1'),
1009 expected)
Christian Heimes5398e1a2013-11-22 16:20:53 +01001010 with self.assertRaisesRegex(ValueError, "unknown object 'serverauth'"):
1011 ssl._ASN1Object.fromname('serverauth')
Christian Heimesa6bc95a2013-11-17 19:59:14 +01001012
Christian Heimes72d28502013-11-23 13:56:58 +01001013 def test_purpose_enum(self):
1014 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1')
1015 self.assertIsInstance(ssl.Purpose.SERVER_AUTH, ssl._ASN1Object)
1016 self.assertEqual(ssl.Purpose.SERVER_AUTH, val)
1017 self.assertEqual(ssl.Purpose.SERVER_AUTH.nid, 129)
1018 self.assertEqual(ssl.Purpose.SERVER_AUTH.shortname, 'serverAuth')
1019 self.assertEqual(ssl.Purpose.SERVER_AUTH.oid,
1020 '1.3.6.1.5.5.7.3.1')
1021
1022 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.2')
1023 self.assertIsInstance(ssl.Purpose.CLIENT_AUTH, ssl._ASN1Object)
1024 self.assertEqual(ssl.Purpose.CLIENT_AUTH, val)
1025 self.assertEqual(ssl.Purpose.CLIENT_AUTH.nid, 130)
1026 self.assertEqual(ssl.Purpose.CLIENT_AUTH.shortname, 'clientAuth')
1027 self.assertEqual(ssl.Purpose.CLIENT_AUTH.oid,
1028 '1.3.6.1.5.5.7.3.2')
1029
Antoine Pitrou3e86ba42013-12-28 17:26:33 +01001030 def test_unsupported_dtls(self):
1031 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
1032 self.addCleanup(s.close)
1033 with self.assertRaises(NotImplementedError) as cx:
Christian Heimesd0486372016-09-10 23:23:33 +02001034 test_wrap_socket(s, cert_reqs=ssl.CERT_NONE)
Antoine Pitrou3e86ba42013-12-28 17:26:33 +01001035 self.assertEqual(str(cx.exception), "only stream sockets are supported")
Christian Heimesa170fa12017-09-15 20:27:30 +02001036 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou3e86ba42013-12-28 17:26:33 +01001037 with self.assertRaises(NotImplementedError) as cx:
1038 ctx.wrap_socket(s)
1039 self.assertEqual(str(cx.exception), "only stream sockets are supported")
1040
Antoine Pitrouc695c952014-04-28 20:57:36 +02001041 def cert_time_ok(self, timestring, timestamp):
1042 self.assertEqual(ssl.cert_time_to_seconds(timestring), timestamp)
1043
1044 def cert_time_fail(self, timestring):
1045 with self.assertRaises(ValueError):
1046 ssl.cert_time_to_seconds(timestring)
1047
1048 @unittest.skipUnless(utc_offset(),
1049 'local time needs to be different from UTC')
1050 def test_cert_time_to_seconds_timezone(self):
1051 # Issue #19940: ssl.cert_time_to_seconds() returns wrong
1052 # results if local timezone is not UTC
1053 self.cert_time_ok("May 9 00:00:00 2007 GMT", 1178668800.0)
1054 self.cert_time_ok("Jan 5 09:34:43 2018 GMT", 1515144883.0)
1055
1056 def test_cert_time_to_seconds(self):
1057 timestring = "Jan 5 09:34:43 2018 GMT"
1058 ts = 1515144883.0
1059 self.cert_time_ok(timestring, ts)
1060 # accept keyword parameter, assert its name
1061 self.assertEqual(ssl.cert_time_to_seconds(cert_time=timestring), ts)
1062 # accept both %e and %d (space or zero generated by strftime)
1063 self.cert_time_ok("Jan 05 09:34:43 2018 GMT", ts)
1064 # case-insensitive
1065 self.cert_time_ok("JaN 5 09:34:43 2018 GmT", ts)
1066 self.cert_time_fail("Jan 5 09:34 2018 GMT") # no seconds
1067 self.cert_time_fail("Jan 5 09:34:43 2018") # no GMT
1068 self.cert_time_fail("Jan 5 09:34:43 2018 UTC") # not GMT timezone
1069 self.cert_time_fail("Jan 35 09:34:43 2018 GMT") # invalid day
1070 self.cert_time_fail("Jon 5 09:34:43 2018 GMT") # invalid month
1071 self.cert_time_fail("Jan 5 24:00:00 2018 GMT") # invalid hour
1072 self.cert_time_fail("Jan 5 09:60:43 2018 GMT") # invalid minute
1073
1074 newyear_ts = 1230768000.0
1075 # leap seconds
1076 self.cert_time_ok("Dec 31 23:59:60 2008 GMT", newyear_ts)
1077 # same timestamp
1078 self.cert_time_ok("Jan 1 00:00:00 2009 GMT", newyear_ts)
1079
1080 self.cert_time_ok("Jan 5 09:34:59 2018 GMT", 1515144899)
1081 # allow 60th second (even if it is not a leap second)
1082 self.cert_time_ok("Jan 5 09:34:60 2018 GMT", 1515144900)
1083 # allow 2nd leap second for compatibility with time.strptime()
1084 self.cert_time_ok("Jan 5 09:34:61 2018 GMT", 1515144901)
1085 self.cert_time_fail("Jan 5 09:34:62 2018 GMT") # invalid seconds
1086
Mike53f7a7c2017-12-14 14:04:53 +03001087 # no special treatment for the special value:
Antoine Pitrouc695c952014-04-28 20:57:36 +02001088 # 99991231235959Z (rfc 5280)
1089 self.cert_time_ok("Dec 31 23:59:59 9999 GMT", 253402300799.0)
1090
1091 @support.run_with_locale('LC_ALL', '')
1092 def test_cert_time_to_seconds_locale(self):
1093 # `cert_time_to_seconds()` should be locale independent
1094
1095 def local_february_name():
1096 return time.strftime('%b', (1, 2, 3, 4, 5, 6, 0, 0, 0))
1097
1098 if local_february_name().lower() == 'feb':
1099 self.skipTest("locale-specific month name needs to be "
1100 "different from C locale")
1101
1102 # locale-independent
1103 self.cert_time_ok("Feb 9 00:00:00 2007 GMT", 1170979200.0)
1104 self.cert_time_fail(local_february_name() + " 9 00:00:00 2007 GMT")
1105
Martin Panter3840b2a2016-03-27 01:53:46 +00001106 def test_connect_ex_error(self):
1107 server = socket.socket(socket.AF_INET)
1108 self.addCleanup(server.close)
Serhiy Storchaka16994912020-04-25 10:06:29 +03001109 port = socket_helper.bind_port(server) # Reserve port but don't listen
Christian Heimesd0486372016-09-10 23:23:33 +02001110 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001111 cert_reqs=ssl.CERT_REQUIRED)
1112 self.addCleanup(s.close)
1113 rc = s.connect_ex((HOST, port))
1114 # Issue #19919: Windows machines or VMs hosted on Windows
1115 # machines sometimes return EWOULDBLOCK.
1116 errors = (
1117 errno.ECONNREFUSED, errno.EHOSTUNREACH, errno.ETIMEDOUT,
1118 errno.EWOULDBLOCK,
1119 )
1120 self.assertIn(rc, errors)
1121
Christian Heimes89d15502021-04-19 06:55:30 +02001122 def test_read_write_zero(self):
1123 # empty reads and writes now work, bpo-42854, bpo-31711
1124 client_context, server_context, hostname = testing_context()
1125 server = ThreadedEchoServer(context=server_context)
1126 with server:
1127 with client_context.wrap_socket(socket.socket(),
1128 server_hostname=hostname) as s:
1129 s.connect((HOST, server.port))
1130 self.assertEqual(s.recv(0), b"")
1131 self.assertEqual(s.send(b""), 0)
1132
Christian Heimesa6bc95a2013-11-17 19:59:14 +01001133
Antoine Pitrou152efa22010-05-16 18:19:27 +00001134class ContextTests(unittest.TestCase):
1135
1136 def test_constructor(self):
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01001137 for protocol in PROTOCOLS:
Christian Heimes2875c602021-04-19 07:27:10 +02001138 with warnings_helper.check_warnings():
1139 ctx = ssl.SSLContext(protocol)
1140 self.assertEqual(ctx.protocol, protocol)
1141 with warnings_helper.check_warnings():
1142 ctx = ssl.SSLContext()
Christian Heimes598894f2016-09-05 23:19:05 +02001143 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001144 self.assertRaises(ValueError, ssl.SSLContext, -1)
1145 self.assertRaises(ValueError, ssl.SSLContext, 42)
1146
Antoine Pitrou152efa22010-05-16 18:19:27 +00001147 def test_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001148 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001149 ctx.set_ciphers("ALL")
1150 ctx.set_ciphers("DEFAULT")
Ezio Melottied3a7d22010-12-01 02:32:32 +00001151 with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
Antoine Pitrou30474062010-05-16 23:46:26 +00001152 ctx.set_ciphers("^$:,;?*'dorothyx")
Antoine Pitrou152efa22010-05-16 18:19:27 +00001153
Christian Heimes892d66e2018-01-29 14:10:18 +01001154 @unittest.skipUnless(PY_SSL_DEFAULT_CIPHERS == 1,
1155 "Test applies only to Python default ciphers")
1156 def test_python_ciphers(self):
1157 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1158 ciphers = ctx.get_ciphers()
1159 for suite in ciphers:
1160 name = suite['name']
1161 self.assertNotIn("PSK", name)
1162 self.assertNotIn("SRP", name)
1163 self.assertNotIn("MD5", name)
1164 self.assertNotIn("RC4", name)
1165 self.assertNotIn("3DES", name)
1166
Christian Heimes25bfcd52016-09-06 00:04:45 +02001167 def test_get_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001168 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesea9b2dc2016-09-06 10:45:44 +02001169 ctx.set_ciphers('AESGCM')
Christian Heimes25bfcd52016-09-06 00:04:45 +02001170 names = set(d['name'] for d in ctx.get_ciphers())
Christian Heimes582282b2016-09-06 11:27:25 +02001171 self.assertIn('AES256-GCM-SHA384', names)
1172 self.assertIn('AES128-GCM-SHA256', names)
Christian Heimes25bfcd52016-09-06 00:04:45 +02001173
Antoine Pitroub5218772010-05-21 09:56:06 +00001174 def test_options(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001175 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Benjamin Petersona9dcdab2015-11-11 22:38:41 -08001176 # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value
Christian Heimes598894f2016-09-05 23:19:05 +02001177 default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
Christian Heimes358cfd42016-09-10 22:43:48 +02001178 # SSLContext also enables these by default
1179 default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE |
Christian Heimes05d9fe32018-02-27 08:55:39 +01001180 OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE |
Christian Heimes6f37ebc2021-04-09 17:59:21 +02001181 OP_ENABLE_MIDDLEBOX_COMPAT |
1182 OP_IGNORE_UNEXPECTED_EOF)
Christian Heimes598894f2016-09-05 23:19:05 +02001183 self.assertEqual(default, ctx.options)
Christian Heimes2875c602021-04-19 07:27:10 +02001184 with warnings_helper.check_warnings():
1185 ctx.options |= ssl.OP_NO_TLSv1
Christian Heimes598894f2016-09-05 23:19:05 +02001186 self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options)
Christian Heimes2875c602021-04-19 07:27:10 +02001187 with warnings_helper.check_warnings():
1188 ctx.options = (ctx.options & ~ssl.OP_NO_TLSv1)
Christian Heimes39258d32021-04-17 11:36:35 +02001189 self.assertEqual(default, ctx.options)
1190 ctx.options = 0
1191 # Ubuntu has OP_NO_SSLv3 forced on by default
1192 self.assertEqual(0, ctx.options & ~ssl.OP_NO_SSLv3)
Antoine Pitroub5218772010-05-21 09:56:06 +00001193
Christian Heimesa170fa12017-09-15 20:27:30 +02001194 def test_verify_mode_protocol(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001195 with warnings_helper.check_warnings():
1196 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001197 # Default value
1198 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1199 ctx.verify_mode = ssl.CERT_OPTIONAL
1200 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1201 ctx.verify_mode = ssl.CERT_REQUIRED
1202 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1203 ctx.verify_mode = ssl.CERT_NONE
1204 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1205 with self.assertRaises(TypeError):
1206 ctx.verify_mode = None
1207 with self.assertRaises(ValueError):
1208 ctx.verify_mode = 42
1209
Christian Heimesa170fa12017-09-15 20:27:30 +02001210 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1211 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1212 self.assertFalse(ctx.check_hostname)
1213
1214 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1215 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1216 self.assertTrue(ctx.check_hostname)
1217
Christian Heimes61d478c2018-01-27 15:51:38 +01001218 def test_hostname_checks_common_name(self):
1219 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1220 self.assertTrue(ctx.hostname_checks_common_name)
1221 if ssl.HAS_NEVER_CHECK_COMMON_NAME:
1222 ctx.hostname_checks_common_name = True
1223 self.assertTrue(ctx.hostname_checks_common_name)
1224 ctx.hostname_checks_common_name = False
1225 self.assertFalse(ctx.hostname_checks_common_name)
1226 ctx.hostname_checks_common_name = True
1227 self.assertTrue(ctx.hostname_checks_common_name)
1228 else:
1229 with self.assertRaises(AttributeError):
1230 ctx.hostname_checks_common_name = True
Christian Heimesa170fa12017-09-15 20:27:30 +02001231
Christian Heimes2875c602021-04-19 07:27:10 +02001232 @ignore_deprecation
Christian Heimes698dde12018-02-27 11:54:43 +01001233 def test_min_max_version(self):
1234 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimes34de2d32019-01-18 16:09:30 +01001235 # OpenSSL default is MINIMUM_SUPPORTED, however some vendors like
1236 # Fedora override the setting to TLS 1.0.
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001237 minimum_range = {
1238 # stock OpenSSL
1239 ssl.TLSVersion.MINIMUM_SUPPORTED,
1240 # Fedora 29 uses TLS 1.0 by default
1241 ssl.TLSVersion.TLSv1,
1242 # RHEL 8 uses TLS 1.2 by default
1243 ssl.TLSVersion.TLSv1_2
1244 }
torsava34864d12019-12-02 17:15:42 +01001245 maximum_range = {
1246 # stock OpenSSL
1247 ssl.TLSVersion.MAXIMUM_SUPPORTED,
1248 # Fedora 32 uses TLS 1.3 by default
1249 ssl.TLSVersion.TLSv1_3
1250 }
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001251
Christian Heimes34de2d32019-01-18 16:09:30 +01001252 self.assertIn(
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001253 ctx.minimum_version, minimum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001254 )
torsava34864d12019-12-02 17:15:42 +01001255 self.assertIn(
1256 ctx.maximum_version, maximum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001257 )
1258
1259 ctx.minimum_version = ssl.TLSVersion.TLSv1_1
1260 ctx.maximum_version = ssl.TLSVersion.TLSv1_2
1261 self.assertEqual(
1262 ctx.minimum_version, ssl.TLSVersion.TLSv1_1
1263 )
1264 self.assertEqual(
1265 ctx.maximum_version, ssl.TLSVersion.TLSv1_2
1266 )
1267
1268 ctx.minimum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1269 ctx.maximum_version = ssl.TLSVersion.TLSv1
1270 self.assertEqual(
1271 ctx.minimum_version, ssl.TLSVersion.MINIMUM_SUPPORTED
1272 )
1273 self.assertEqual(
1274 ctx.maximum_version, ssl.TLSVersion.TLSv1
1275 )
1276
1277 ctx.maximum_version = ssl.TLSVersion.MAXIMUM_SUPPORTED
1278 self.assertEqual(
1279 ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED
1280 )
1281
1282 ctx.maximum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1283 self.assertIn(
1284 ctx.maximum_version,
1285 {ssl.TLSVersion.TLSv1, ssl.TLSVersion.SSLv3}
1286 )
1287
1288 ctx.minimum_version = ssl.TLSVersion.MAXIMUM_SUPPORTED
1289 self.assertIn(
1290 ctx.minimum_version,
1291 {ssl.TLSVersion.TLSv1_2, ssl.TLSVersion.TLSv1_3}
1292 )
1293
1294 with self.assertRaises(ValueError):
1295 ctx.minimum_version = 42
1296
1297 ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_1)
1298
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001299 self.assertIn(
1300 ctx.minimum_version, minimum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001301 )
1302 self.assertEqual(
1303 ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED
1304 )
1305 with self.assertRaises(ValueError):
1306 ctx.minimum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1307 with self.assertRaises(ValueError):
1308 ctx.maximum_version = ssl.TLSVersion.TLSv1
1309
1310
matthewhughes9348e836bb2020-07-17 09:59:15 +01001311 @unittest.skipUnless(
1312 hasattr(ssl.SSLContext, 'security_level'),
1313 "requires OpenSSL >= 1.1.0"
1314 )
1315 def test_security_level(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001316 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
matthewhughes9348e836bb2020-07-17 09:59:15 +01001317 # The default security callback allows for levels between 0-5
1318 # with OpenSSL defaulting to 1, however some vendors override the
1319 # default value (e.g. Debian defaults to 2)
1320 security_level_range = {
1321 0,
1322 1, # OpenSSL default
1323 2, # Debian
1324 3,
1325 4,
1326 5,
1327 }
1328 self.assertIn(ctx.security_level, security_level_range)
1329
Christian Heimes22587792013-11-21 23:56:13 +01001330 def test_verify_flags(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001331 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Benjamin Peterson990fcaa2015-03-04 22:49:41 -05001332 # default value
1333 tf = getattr(ssl, "VERIFY_X509_TRUSTED_FIRST", 0)
1334 self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT | tf)
Christian Heimes22587792013-11-21 23:56:13 +01001335 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF
1336 self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_LEAF)
1337 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_CHAIN
1338 self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_CHAIN)
1339 ctx.verify_flags = ssl.VERIFY_DEFAULT
1340 self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT)
Chris Burre0b4aa02021-03-18 09:24:01 +01001341 ctx.verify_flags = ssl.VERIFY_ALLOW_PROXY_CERTS
1342 self.assertEqual(ctx.verify_flags, ssl.VERIFY_ALLOW_PROXY_CERTS)
Christian Heimes22587792013-11-21 23:56:13 +01001343 # supports any value
1344 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT
1345 self.assertEqual(ctx.verify_flags,
1346 ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT)
1347 with self.assertRaises(TypeError):
1348 ctx.verify_flags = None
1349
Antoine Pitrou152efa22010-05-16 18:19:27 +00001350 def test_load_cert_chain(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001351 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001352 # Combined key and cert in a single file
Benjamin Peterson1ea070e2014-11-03 21:05:01 -05001353 ctx.load_cert_chain(CERTFILE, keyfile=None)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001354 ctx.load_cert_chain(CERTFILE, keyfile=CERTFILE)
1355 self.assertRaises(TypeError, ctx.load_cert_chain, keyfile=CERTFILE)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001356 with self.assertRaises(OSError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001357 ctx.load_cert_chain(NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +00001358 self.assertEqual(cm.exception.errno, errno.ENOENT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001359 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001360 ctx.load_cert_chain(BADCERT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001361 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001362 ctx.load_cert_chain(EMPTYCERT)
1363 # Separate key and cert
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_cert_chain(ONLYCERT, ONLYKEY)
1366 ctx.load_cert_chain(certfile=ONLYCERT, keyfile=ONLYKEY)
1367 ctx.load_cert_chain(certfile=BYTES_ONLYCERT, keyfile=BYTES_ONLYKEY)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001368 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001369 ctx.load_cert_chain(ONLYCERT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001370 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001371 ctx.load_cert_chain(ONLYKEY)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001372 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001373 ctx.load_cert_chain(certfile=ONLYKEY, keyfile=ONLYCERT)
1374 # Mismatching key and cert
Christian Heimesa170fa12017-09-15 20:27:30 +02001375 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001376 with self.assertRaisesRegex(ssl.SSLError, "key values mismatch"):
Martin Panter3d81d932016-01-14 09:36:00 +00001377 ctx.load_cert_chain(CAFILE_CACERT, ONLYKEY)
Antoine Pitrou4fd1e6a2011-08-25 14:39:44 +02001378 # Password protected key and cert
1379 ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD)
1380 ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD.encode())
1381 ctx.load_cert_chain(CERTFILE_PROTECTED,
1382 password=bytearray(KEY_PASSWORD.encode()))
1383 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD)
1384 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD.encode())
1385 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED,
1386 bytearray(KEY_PASSWORD.encode()))
1387 with self.assertRaisesRegex(TypeError, "should be a string"):
1388 ctx.load_cert_chain(CERTFILE_PROTECTED, password=True)
1389 with self.assertRaises(ssl.SSLError):
1390 ctx.load_cert_chain(CERTFILE_PROTECTED, password="badpass")
1391 with self.assertRaisesRegex(ValueError, "cannot be longer"):
1392 # openssl has a fixed limit on the password buffer.
1393 # PEM_BUFSIZE is generally set to 1kb.
1394 # Return a string larger than this.
1395 ctx.load_cert_chain(CERTFILE_PROTECTED, password=b'a' * 102400)
1396 # Password callback
1397 def getpass_unicode():
1398 return KEY_PASSWORD
1399 def getpass_bytes():
1400 return KEY_PASSWORD.encode()
1401 def getpass_bytearray():
1402 return bytearray(KEY_PASSWORD.encode())
1403 def getpass_badpass():
1404 return "badpass"
1405 def getpass_huge():
1406 return b'a' * (1024 * 1024)
1407 def getpass_bad_type():
1408 return 9
1409 def getpass_exception():
1410 raise Exception('getpass error')
1411 class GetPassCallable:
1412 def __call__(self):
1413 return KEY_PASSWORD
1414 def getpass(self):
1415 return KEY_PASSWORD
1416 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_unicode)
1417 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytes)
1418 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytearray)
1419 ctx.load_cert_chain(CERTFILE_PROTECTED, password=GetPassCallable())
1420 ctx.load_cert_chain(CERTFILE_PROTECTED,
1421 password=GetPassCallable().getpass)
1422 with self.assertRaises(ssl.SSLError):
1423 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_badpass)
1424 with self.assertRaisesRegex(ValueError, "cannot be longer"):
1425 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_huge)
1426 with self.assertRaisesRegex(TypeError, "must return a string"):
1427 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bad_type)
1428 with self.assertRaisesRegex(Exception, "getpass error"):
1429 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_exception)
1430 # Make sure the password function isn't called if it isn't needed
1431 ctx.load_cert_chain(CERTFILE, password=getpass_exception)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001432
1433 def test_load_verify_locations(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001434 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001435 ctx.load_verify_locations(CERTFILE)
1436 ctx.load_verify_locations(cafile=CERTFILE, capath=None)
1437 ctx.load_verify_locations(BYTES_CERTFILE)
1438 ctx.load_verify_locations(cafile=BYTES_CERTFILE, capath=None)
1439 self.assertRaises(TypeError, ctx.load_verify_locations)
Christian Heimesefff7062013-11-21 03:35:02 +01001440 self.assertRaises(TypeError, ctx.load_verify_locations, None, None, None)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001441 with self.assertRaises(OSError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001442 ctx.load_verify_locations(NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +00001443 self.assertEqual(cm.exception.errno, errno.ENOENT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001444 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001445 ctx.load_verify_locations(BADCERT)
1446 ctx.load_verify_locations(CERTFILE, CAPATH)
1447 ctx.load_verify_locations(CERTFILE, capath=BYTES_CAPATH)
1448
Victor Stinner80f75e62011-01-29 11:31:20 +00001449 # Issue #10989: crash if the second argument type is invalid
1450 self.assertRaises(TypeError, ctx.load_verify_locations, None, True)
1451
Christian Heimesefff7062013-11-21 03:35:02 +01001452 def test_load_verify_cadata(self):
1453 # test cadata
1454 with open(CAFILE_CACERT) as f:
1455 cacert_pem = f.read()
1456 cacert_der = ssl.PEM_cert_to_DER_cert(cacert_pem)
1457 with open(CAFILE_NEURONIO) as f:
1458 neuronio_pem = f.read()
1459 neuronio_der = ssl.PEM_cert_to_DER_cert(neuronio_pem)
1460
1461 # test PEM
Christian Heimesa170fa12017-09-15 20:27:30 +02001462 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001463 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 0)
1464 ctx.load_verify_locations(cadata=cacert_pem)
1465 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 1)
1466 ctx.load_verify_locations(cadata=neuronio_pem)
1467 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1468 # cert already in hash table
1469 ctx.load_verify_locations(cadata=neuronio_pem)
1470 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1471
1472 # combined
Christian Heimesa170fa12017-09-15 20:27:30 +02001473 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001474 combined = "\n".join((cacert_pem, neuronio_pem))
1475 ctx.load_verify_locations(cadata=combined)
1476 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1477
1478 # with junk around the certs
Christian Heimesa170fa12017-09-15 20:27:30 +02001479 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001480 combined = ["head", cacert_pem, "other", neuronio_pem, "again",
1481 neuronio_pem, "tail"]
1482 ctx.load_verify_locations(cadata="\n".join(combined))
1483 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1484
1485 # test DER
Christian Heimesa170fa12017-09-15 20:27:30 +02001486 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001487 ctx.load_verify_locations(cadata=cacert_der)
1488 ctx.load_verify_locations(cadata=neuronio_der)
1489 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1490 # cert already in hash table
1491 ctx.load_verify_locations(cadata=cacert_der)
1492 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1493
1494 # combined
Christian Heimesa170fa12017-09-15 20:27:30 +02001495 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001496 combined = b"".join((cacert_der, neuronio_der))
1497 ctx.load_verify_locations(cadata=combined)
1498 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1499
1500 # error cases
Christian Heimesa170fa12017-09-15 20:27:30 +02001501 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001502 self.assertRaises(TypeError, ctx.load_verify_locations, cadata=object)
1503
Christian Heimesb9ad88b2021-04-23 13:51:40 +02001504 with self.assertRaisesRegex(
1505 ssl.SSLError,
1506 "no start line: cadata does not contain a certificate"
1507 ):
Christian Heimesefff7062013-11-21 03:35:02 +01001508 ctx.load_verify_locations(cadata="broken")
Christian Heimesb9ad88b2021-04-23 13:51:40 +02001509 with self.assertRaisesRegex(
1510 ssl.SSLError,
1511 "not enough data: cadata does not contain a certificate"
1512 ):
Christian Heimesefff7062013-11-21 03:35:02 +01001513 ctx.load_verify_locations(cadata=b"broken")
1514
Paul Monsonf3550692019-06-19 13:09:54 -07001515 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001516 def test_load_dh_params(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001517 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001518 ctx.load_dh_params(DHFILE)
1519 if os.name != 'nt':
1520 ctx.load_dh_params(BYTES_DHFILE)
1521 self.assertRaises(TypeError, ctx.load_dh_params)
1522 self.assertRaises(TypeError, ctx.load_dh_params, None)
1523 with self.assertRaises(FileNotFoundError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001524 ctx.load_dh_params(NONEXISTINGCERT)
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001525 self.assertEqual(cm.exception.errno, errno.ENOENT)
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001526 with self.assertRaises(ssl.SSLError) as cm:
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001527 ctx.load_dh_params(CERTFILE)
1528
Antoine Pitroub0182c82010-10-12 20:09:02 +00001529 def test_session_stats(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001530 for proto in {ssl.PROTOCOL_TLS_CLIENT, ssl.PROTOCOL_TLS_SERVER}:
Antoine Pitroub0182c82010-10-12 20:09:02 +00001531 ctx = ssl.SSLContext(proto)
1532 self.assertEqual(ctx.session_stats(), {
1533 'number': 0,
1534 'connect': 0,
1535 'connect_good': 0,
1536 'connect_renegotiate': 0,
1537 'accept': 0,
1538 'accept_good': 0,
1539 'accept_renegotiate': 0,
1540 'hits': 0,
1541 'misses': 0,
1542 'timeouts': 0,
1543 'cache_full': 0,
1544 })
1545
Antoine Pitrou664c2d12010-11-17 20:29:42 +00001546 def test_set_default_verify_paths(self):
1547 # There's not much we can do to test that it acts as expected,
1548 # so just check it doesn't crash or raise an exception.
Christian Heimesa170fa12017-09-15 20:27:30 +02001549 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou664c2d12010-11-17 20:29:42 +00001550 ctx.set_default_verify_paths()
1551
Antoine Pitrou501da612011-12-21 09:27:41 +01001552 @unittest.skipUnless(ssl.HAS_ECDH, "ECDH disabled on this OpenSSL build")
Antoine Pitrou923df6f2011-12-19 17:16:51 +01001553 def test_set_ecdh_curve(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001554 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou923df6f2011-12-19 17:16:51 +01001555 ctx.set_ecdh_curve("prime256v1")
1556 ctx.set_ecdh_curve(b"prime256v1")
1557 self.assertRaises(TypeError, ctx.set_ecdh_curve)
1558 self.assertRaises(TypeError, ctx.set_ecdh_curve, None)
1559 self.assertRaises(ValueError, ctx.set_ecdh_curve, "foo")
1560 self.assertRaises(ValueError, ctx.set_ecdh_curve, b"foo")
1561
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001562 def test_sni_callback(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001563 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001564
1565 # set_servername_callback expects a callable, or None
1566 self.assertRaises(TypeError, ctx.set_servername_callback)
1567 self.assertRaises(TypeError, ctx.set_servername_callback, 4)
1568 self.assertRaises(TypeError, ctx.set_servername_callback, "")
1569 self.assertRaises(TypeError, ctx.set_servername_callback, ctx)
1570
1571 def dummycallback(sock, servername, ctx):
1572 pass
1573 ctx.set_servername_callback(None)
1574 ctx.set_servername_callback(dummycallback)
1575
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001576 def test_sni_callback_refcycle(self):
1577 # Reference cycles through the servername callback are detected
1578 # and cleared.
Christian Heimesa170fa12017-09-15 20:27:30 +02001579 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001580 def dummycallback(sock, servername, ctx, cycle=ctx):
1581 pass
1582 ctx.set_servername_callback(dummycallback)
1583 wr = weakref.ref(ctx)
1584 del ctx, dummycallback
1585 gc.collect()
1586 self.assertIs(wr(), None)
1587
Christian Heimes9a5395a2013-06-17 15:44:12 +02001588 def test_cert_store_stats(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001589 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001590 self.assertEqual(ctx.cert_store_stats(),
1591 {'x509_ca': 0, 'crl': 0, 'x509': 0})
1592 ctx.load_cert_chain(CERTFILE)
1593 self.assertEqual(ctx.cert_store_stats(),
1594 {'x509_ca': 0, 'crl': 0, 'x509': 0})
1595 ctx.load_verify_locations(CERTFILE)
1596 self.assertEqual(ctx.cert_store_stats(),
1597 {'x509_ca': 0, 'crl': 0, 'x509': 1})
Martin Panterb55f8b72016-01-14 12:53:56 +00001598 ctx.load_verify_locations(CAFILE_CACERT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001599 self.assertEqual(ctx.cert_store_stats(),
1600 {'x509_ca': 1, 'crl': 0, 'x509': 2})
1601
1602 def test_get_ca_certs(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001603 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001604 self.assertEqual(ctx.get_ca_certs(), [])
1605 # CERTFILE is not flagged as X509v3 Basic Constraints: CA:TRUE
1606 ctx.load_verify_locations(CERTFILE)
1607 self.assertEqual(ctx.get_ca_certs(), [])
Martin Panterb55f8b72016-01-14 12:53:56 +00001608 # but CAFILE_CACERT is a CA cert
1609 ctx.load_verify_locations(CAFILE_CACERT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001610 self.assertEqual(ctx.get_ca_certs(),
1611 [{'issuer': ((('organizationName', 'Root CA'),),
1612 (('organizationalUnitName', 'http://www.cacert.org'),),
1613 (('commonName', 'CA Cert Signing Authority'),),
1614 (('emailAddress', 'support@cacert.org'),)),
Christian Heimesd37b74f2021-04-19 08:31:29 +02001615 'notAfter': 'Mar 29 12:29:49 2033 GMT',
1616 'notBefore': 'Mar 30 12:29:49 2003 GMT',
Christian Heimes9a5395a2013-06-17 15:44:12 +02001617 'serialNumber': '00',
Christian Heimesbd3a7f92013-11-21 03:40:15 +01001618 'crlDistributionPoints': ('https://www.cacert.org/revoke.crl',),
Christian Heimes9a5395a2013-06-17 15:44:12 +02001619 'subject': ((('organizationName', 'Root CA'),),
1620 (('organizationalUnitName', 'http://www.cacert.org'),),
1621 (('commonName', 'CA Cert Signing Authority'),),
1622 (('emailAddress', 'support@cacert.org'),)),
1623 'version': 3}])
1624
Martin Panterb55f8b72016-01-14 12:53:56 +00001625 with open(CAFILE_CACERT) as f:
Christian Heimes9a5395a2013-06-17 15:44:12 +02001626 pem = f.read()
1627 der = ssl.PEM_cert_to_DER_cert(pem)
1628 self.assertEqual(ctx.get_ca_certs(True), [der])
1629
Christian Heimes72d28502013-11-23 13:56:58 +01001630 def test_load_default_certs(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001631 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001632 ctx.load_default_certs()
1633
Christian Heimesa170fa12017-09-15 20:27:30 +02001634 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001635 ctx.load_default_certs(ssl.Purpose.SERVER_AUTH)
1636 ctx.load_default_certs()
1637
Christian Heimesa170fa12017-09-15 20:27:30 +02001638 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001639 ctx.load_default_certs(ssl.Purpose.CLIENT_AUTH)
1640
Christian Heimesa170fa12017-09-15 20:27:30 +02001641 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001642 self.assertRaises(TypeError, ctx.load_default_certs, None)
1643 self.assertRaises(TypeError, ctx.load_default_certs, 'SERVER_AUTH')
1644
Benjamin Peterson91244e02014-10-03 18:17:15 -04001645 @unittest.skipIf(sys.platform == "win32", "not-Windows specific")
Benjamin Peterson5915b0f2014-10-03 17:27:05 -04001646 def test_load_default_certs_env(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001647 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Hai Shia7f5d932020-08-04 00:41:24 +08001648 with os_helper.EnvironmentVarGuard() as env:
Benjamin Peterson5915b0f2014-10-03 17:27:05 -04001649 env["SSL_CERT_DIR"] = CAPATH
1650 env["SSL_CERT_FILE"] = CERTFILE
1651 ctx.load_default_certs()
1652 self.assertEqual(ctx.cert_store_stats(), {"crl": 0, "x509": 1, "x509_ca": 0})
1653
Benjamin Peterson91244e02014-10-03 18:17:15 -04001654 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
Steve Dower68d663c2017-07-17 11:15:48 +02001655 @unittest.skipIf(hasattr(sys, "gettotalrefcount"), "Debug build does not share environment between CRTs")
Benjamin Peterson91244e02014-10-03 18:17:15 -04001656 def test_load_default_certs_env_windows(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001657 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Benjamin Peterson91244e02014-10-03 18:17:15 -04001658 ctx.load_default_certs()
1659 stats = ctx.cert_store_stats()
1660
Christian Heimesa170fa12017-09-15 20:27:30 +02001661 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Hai Shia7f5d932020-08-04 00:41:24 +08001662 with os_helper.EnvironmentVarGuard() as env:
Benjamin Peterson91244e02014-10-03 18:17:15 -04001663 env["SSL_CERT_DIR"] = CAPATH
1664 env["SSL_CERT_FILE"] = CERTFILE
1665 ctx.load_default_certs()
1666 stats["x509"] += 1
1667 self.assertEqual(ctx.cert_store_stats(), stats)
1668
Christian Heimes358cfd42016-09-10 22:43:48 +02001669 def _assert_context_options(self, ctx):
1670 self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
1671 if OP_NO_COMPRESSION != 0:
1672 self.assertEqual(ctx.options & OP_NO_COMPRESSION,
1673 OP_NO_COMPRESSION)
1674 if OP_SINGLE_DH_USE != 0:
1675 self.assertEqual(ctx.options & OP_SINGLE_DH_USE,
1676 OP_SINGLE_DH_USE)
1677 if OP_SINGLE_ECDH_USE != 0:
1678 self.assertEqual(ctx.options & OP_SINGLE_ECDH_USE,
1679 OP_SINGLE_ECDH_USE)
1680 if OP_CIPHER_SERVER_PREFERENCE != 0:
1681 self.assertEqual(ctx.options & OP_CIPHER_SERVER_PREFERENCE,
1682 OP_CIPHER_SERVER_PREFERENCE)
1683
Christian Heimes4c05b472013-11-23 15:58:30 +01001684 def test_create_default_context(self):
1685 ctx = ssl.create_default_context()
Christian Heimes358cfd42016-09-10 22:43:48 +02001686
Christian Heimes2875c602021-04-19 07:27:10 +02001687 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes4c05b472013-11-23 15:58:30 +01001688 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001689 self.assertTrue(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001690 self._assert_context_options(ctx)
1691
Christian Heimes4c05b472013-11-23 15:58:30 +01001692 with open(SIGNING_CA) as f:
1693 cadata = f.read()
1694 ctx = ssl.create_default_context(cafile=SIGNING_CA, capath=CAPATH,
1695 cadata=cadata)
Christian Heimes2875c602021-04-19 07:27:10 +02001696 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes4c05b472013-11-23 15:58:30 +01001697 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes358cfd42016-09-10 22:43:48 +02001698 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001699
1700 ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
Christian Heimes2875c602021-04-19 07:27:10 +02001701 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_SERVER)
Christian Heimes4c05b472013-11-23 15:58:30 +01001702 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001703 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001704
Christian Heimes2875c602021-04-19 07:27:10 +02001705
1706
Christian Heimes67986f92013-11-23 22:43:47 +01001707 def test__create_stdlib_context(self):
1708 ctx = ssl._create_stdlib_context()
Christian Heimes2875c602021-04-19 07:27:10 +02001709 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes67986f92013-11-23 22:43:47 +01001710 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001711 self.assertFalse(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001712 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001713
Christian Heimes2875c602021-04-19 07:27:10 +02001714 with warnings_helper.check_warnings():
1715 ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1)
Christian Heimes67986f92013-11-23 22:43:47 +01001716 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
1717 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001718 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001719
Christian Heimes2875c602021-04-19 07:27:10 +02001720 with warnings_helper.check_warnings():
1721 ctx = ssl._create_stdlib_context(
1722 ssl.PROTOCOL_TLSv1_2,
1723 cert_reqs=ssl.CERT_REQUIRED,
1724 check_hostname=True
1725 )
1726 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1_2)
Christian Heimes67986f92013-11-23 22:43:47 +01001727 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimesa02c69a2013-12-02 20:59:28 +01001728 self.assertTrue(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001729 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001730
1731 ctx = ssl._create_stdlib_context(purpose=ssl.Purpose.CLIENT_AUTH)
Christian Heimes2875c602021-04-19 07:27:10 +02001732 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_SERVER)
Christian Heimes67986f92013-11-23 22:43:47 +01001733 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001734 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001735
Christian Heimes1aa9a752013-12-02 02:41:19 +01001736 def test_check_hostname(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001737 with warnings_helper.check_warnings():
1738 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001739 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001740 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001741
Christian Heimese82c0342017-09-15 20:29:57 +02001742 # Auto set CERT_REQUIRED
1743 ctx.check_hostname = True
1744 self.assertTrue(ctx.check_hostname)
1745 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1746 ctx.check_hostname = False
Christian Heimes1aa9a752013-12-02 02:41:19 +01001747 ctx.verify_mode = ssl.CERT_REQUIRED
1748 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001749 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001750
Christian Heimese82c0342017-09-15 20:29:57 +02001751 # Changing verify_mode does not affect check_hostname
1752 ctx.check_hostname = False
1753 ctx.verify_mode = ssl.CERT_NONE
1754 ctx.check_hostname = False
1755 self.assertFalse(ctx.check_hostname)
1756 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1757 # Auto set
Christian Heimes1aa9a752013-12-02 02:41:19 +01001758 ctx.check_hostname = True
1759 self.assertTrue(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001760 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1761
1762 ctx.check_hostname = False
1763 ctx.verify_mode = ssl.CERT_OPTIONAL
1764 ctx.check_hostname = False
1765 self.assertFalse(ctx.check_hostname)
1766 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1767 # keep CERT_OPTIONAL
1768 ctx.check_hostname = True
1769 self.assertTrue(ctx.check_hostname)
1770 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001771
1772 # Cannot set CERT_NONE with check_hostname enabled
1773 with self.assertRaises(ValueError):
1774 ctx.verify_mode = ssl.CERT_NONE
1775 ctx.check_hostname = False
1776 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001777 ctx.verify_mode = ssl.CERT_NONE
1778 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001779
Christian Heimes5fe668c2016-09-12 00:01:11 +02001780 def test_context_client_server(self):
1781 # PROTOCOL_TLS_CLIENT has sane defaults
1782 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1783 self.assertTrue(ctx.check_hostname)
1784 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1785
1786 # PROTOCOL_TLS_SERVER has different but also sane defaults
1787 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1788 self.assertFalse(ctx.check_hostname)
1789 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1790
Christian Heimes4df60f12017-09-15 20:26:05 +02001791 def test_context_custom_class(self):
1792 class MySSLSocket(ssl.SSLSocket):
1793 pass
1794
1795 class MySSLObject(ssl.SSLObject):
1796 pass
1797
1798 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1799 ctx.sslsocket_class = MySSLSocket
1800 ctx.sslobject_class = MySSLObject
1801
1802 with ctx.wrap_socket(socket.socket(), server_side=True) as sock:
1803 self.assertIsInstance(sock, MySSLSocket)
Miss Islington (bot)d7930fb2021-06-11 00:36:17 -07001804 obj = ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(), server_side=True)
Christian Heimes4df60f12017-09-15 20:26:05 +02001805 self.assertIsInstance(obj, MySSLObject)
1806
Christian Heimes78c7d522019-06-03 21:00:10 +02001807 def test_num_tickest(self):
1808 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1809 self.assertEqual(ctx.num_tickets, 2)
1810 ctx.num_tickets = 1
1811 self.assertEqual(ctx.num_tickets, 1)
1812 ctx.num_tickets = 0
1813 self.assertEqual(ctx.num_tickets, 0)
1814 with self.assertRaises(ValueError):
1815 ctx.num_tickets = -1
1816 with self.assertRaises(TypeError):
1817 ctx.num_tickets = None
1818
1819 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1820 self.assertEqual(ctx.num_tickets, 2)
1821 with self.assertRaises(ValueError):
1822 ctx.num_tickets = 1
1823
Antoine Pitrou152efa22010-05-16 18:19:27 +00001824
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001825class SSLErrorTests(unittest.TestCase):
1826
1827 def test_str(self):
1828 # The str() of a SSLError doesn't include the errno
1829 e = ssl.SSLError(1, "foo")
1830 self.assertEqual(str(e), "foo")
1831 self.assertEqual(e.errno, 1)
1832 # Same for a subclass
1833 e = ssl.SSLZeroReturnError(1, "foo")
1834 self.assertEqual(str(e), "foo")
1835 self.assertEqual(e.errno, 1)
1836
Paul Monsonf3550692019-06-19 13:09:54 -07001837 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001838 def test_lib_reason(self):
1839 # Test the library and reason attributes
Christian Heimesa170fa12017-09-15 20:27:30 +02001840 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001841 with self.assertRaises(ssl.SSLError) as cm:
1842 ctx.load_dh_params(CERTFILE)
1843 self.assertEqual(cm.exception.library, 'PEM')
1844 self.assertEqual(cm.exception.reason, 'NO_START_LINE')
1845 s = str(cm.exception)
1846 self.assertTrue(s.startswith("[PEM: NO_START_LINE] no start line"), s)
1847
1848 def test_subclass(self):
1849 # Check that the appropriate SSLError subclass is raised
1850 # (this only tests one of them)
Christian Heimesa170fa12017-09-15 20:27:30 +02001851 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1852 ctx.check_hostname = False
1853 ctx.verify_mode = ssl.CERT_NONE
Giampaolo Rodolaeb7e29f2019-04-09 00:34:02 +02001854 with socket.create_server(("127.0.0.1", 0)) as s:
1855 c = socket.create_connection(s.getsockname())
Antoine Pitroue1ceb502013-01-12 21:54:44 +01001856 c.setblocking(False)
1857 with ctx.wrap_socket(c, False, do_handshake_on_connect=False) as c:
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001858 with self.assertRaises(ssl.SSLWantReadError) as cm:
1859 c.do_handshake()
1860 s = str(cm.exception)
1861 self.assertTrue(s.startswith("The operation did not complete (read)"), s)
1862 # For compatibility
1863 self.assertEqual(cm.exception.errno, ssl.SSL_ERROR_WANT_READ)
1864
1865
Christian Heimes61d478c2018-01-27 15:51:38 +01001866 def test_bad_server_hostname(self):
1867 ctx = ssl.create_default_context()
1868 with self.assertRaises(ValueError):
1869 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1870 server_hostname="")
1871 with self.assertRaises(ValueError):
1872 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1873 server_hostname=".example.org")
Christian Heimesd02ac252018-03-25 12:36:13 +02001874 with self.assertRaises(TypeError):
1875 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1876 server_hostname="example.org\x00evil.com")
Christian Heimes61d478c2018-01-27 15:51:38 +01001877
1878
Antoine Pitroub1fdf472014-10-05 20:41:53 +02001879class MemoryBIOTests(unittest.TestCase):
1880
1881 def test_read_write(self):
1882 bio = ssl.MemoryBIO()
1883 bio.write(b'foo')
1884 self.assertEqual(bio.read(), b'foo')
1885 self.assertEqual(bio.read(), b'')
1886 bio.write(b'foo')
1887 bio.write(b'bar')
1888 self.assertEqual(bio.read(), b'foobar')
1889 self.assertEqual(bio.read(), b'')
1890 bio.write(b'baz')
1891 self.assertEqual(bio.read(2), b'ba')
1892 self.assertEqual(bio.read(1), b'z')
1893 self.assertEqual(bio.read(1), b'')
1894
1895 def test_eof(self):
1896 bio = ssl.MemoryBIO()
1897 self.assertFalse(bio.eof)
1898 self.assertEqual(bio.read(), b'')
1899 self.assertFalse(bio.eof)
1900 bio.write(b'foo')
1901 self.assertFalse(bio.eof)
1902 bio.write_eof()
1903 self.assertFalse(bio.eof)
1904 self.assertEqual(bio.read(2), b'fo')
1905 self.assertFalse(bio.eof)
1906 self.assertEqual(bio.read(1), b'o')
1907 self.assertTrue(bio.eof)
1908 self.assertEqual(bio.read(), b'')
1909 self.assertTrue(bio.eof)
1910
1911 def test_pending(self):
1912 bio = ssl.MemoryBIO()
1913 self.assertEqual(bio.pending, 0)
1914 bio.write(b'foo')
1915 self.assertEqual(bio.pending, 3)
1916 for i in range(3):
1917 bio.read(1)
1918 self.assertEqual(bio.pending, 3-i-1)
1919 for i in range(3):
1920 bio.write(b'x')
1921 self.assertEqual(bio.pending, i+1)
1922 bio.read()
1923 self.assertEqual(bio.pending, 0)
1924
1925 def test_buffer_types(self):
1926 bio = ssl.MemoryBIO()
1927 bio.write(b'foo')
1928 self.assertEqual(bio.read(), b'foo')
1929 bio.write(bytearray(b'bar'))
1930 self.assertEqual(bio.read(), b'bar')
1931 bio.write(memoryview(b'baz'))
1932 self.assertEqual(bio.read(), b'baz')
1933
1934 def test_error_types(self):
1935 bio = ssl.MemoryBIO()
1936 self.assertRaises(TypeError, bio.write, 'foo')
1937 self.assertRaises(TypeError, bio.write, None)
1938 self.assertRaises(TypeError, bio.write, True)
1939 self.assertRaises(TypeError, bio.write, 1)
1940
1941
Christian Heimes9d50ab52018-02-27 10:17:30 +01001942class SSLObjectTests(unittest.TestCase):
1943 def test_private_init(self):
1944 bio = ssl.MemoryBIO()
1945 with self.assertRaisesRegex(TypeError, "public constructor"):
1946 ssl.SSLObject(bio, bio)
1947
Nathaniel J. Smithc0da5822018-09-21 21:44:12 -07001948 def test_unwrap(self):
1949 client_ctx, server_ctx, hostname = testing_context()
1950 c_in = ssl.MemoryBIO()
1951 c_out = ssl.MemoryBIO()
1952 s_in = ssl.MemoryBIO()
1953 s_out = ssl.MemoryBIO()
1954 client = client_ctx.wrap_bio(c_in, c_out, server_hostname=hostname)
1955 server = server_ctx.wrap_bio(s_in, s_out, server_side=True)
1956
1957 # Loop on the handshake for a bit to get it settled
1958 for _ in range(5):
1959 try:
1960 client.do_handshake()
1961 except ssl.SSLWantReadError:
1962 pass
1963 if c_out.pending:
1964 s_in.write(c_out.read())
1965 try:
1966 server.do_handshake()
1967 except ssl.SSLWantReadError:
1968 pass
1969 if s_out.pending:
1970 c_in.write(s_out.read())
1971 # Now the handshakes should be complete (don't raise WantReadError)
1972 client.do_handshake()
1973 server.do_handshake()
1974
1975 # Now if we unwrap one side unilaterally, it should send close-notify
1976 # and raise WantReadError:
1977 with self.assertRaises(ssl.SSLWantReadError):
1978 client.unwrap()
1979
1980 # But server.unwrap() does not raise, because it reads the client's
1981 # close-notify:
1982 s_in.write(c_out.read())
1983 server.unwrap()
1984
1985 # And now that the client gets the server's close-notify, it doesn't
1986 # raise either.
1987 c_in.write(s_out.read())
1988 client.unwrap()
Christian Heimes9d50ab52018-02-27 10:17:30 +01001989
Martin Panter3840b2a2016-03-27 01:53:46 +00001990class SimpleBackgroundTests(unittest.TestCase):
Martin Panter3840b2a2016-03-27 01:53:46 +00001991 """Tests that connect to a simple server running in the background"""
1992
1993 def setUp(self):
juhovh49fdf112021-04-18 21:11:48 +10001994 self.server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1995 self.server_context.load_cert_chain(SIGNED_CERTFILE)
1996 server = ThreadedEchoServer(context=self.server_context)
Martin Panter3840b2a2016-03-27 01:53:46 +00001997 self.server_addr = (HOST, server.port)
1998 server.__enter__()
1999 self.addCleanup(server.__exit__, None, None, None)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002000
Antoine Pitrou480a1242010-04-28 21:37:09 +00002001 def test_connect(self):
Christian Heimesd0486372016-09-10 23:23:33 +02002002 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002003 cert_reqs=ssl.CERT_NONE) as s:
2004 s.connect(self.server_addr)
2005 self.assertEqual({}, s.getpeercert())
Christian Heimesa5d07652016-09-24 10:48:05 +02002006 self.assertFalse(s.server_side)
Antoine Pitrou350c7222010-09-09 13:31:46 +00002007
Martin Panter3840b2a2016-03-27 01:53:46 +00002008 # this should succeed because we specify the root cert
Christian Heimesd0486372016-09-10 23:23:33 +02002009 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002010 cert_reqs=ssl.CERT_REQUIRED,
2011 ca_certs=SIGNING_CA) as s:
2012 s.connect(self.server_addr)
2013 self.assertTrue(s.getpeercert())
Christian Heimesa5d07652016-09-24 10:48:05 +02002014 self.assertFalse(s.server_side)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002015
Martin Panter3840b2a2016-03-27 01:53:46 +00002016 def test_connect_fail(self):
2017 # This should fail because we have no verification certs. Connection
2018 # failure crashes ThreadedEchoServer, so run this in an independent
2019 # test method.
Christian Heimesd0486372016-09-10 23:23:33 +02002020 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002021 cert_reqs=ssl.CERT_REQUIRED)
2022 self.addCleanup(s.close)
2023 self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
2024 s.connect, self.server_addr)
Antoine Pitrou152efa22010-05-16 18:19:27 +00002025
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002026 def test_connect_ex(self):
2027 # Issue #11326: check connect_ex() implementation
Christian Heimesd0486372016-09-10 23:23:33 +02002028 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002029 cert_reqs=ssl.CERT_REQUIRED,
2030 ca_certs=SIGNING_CA)
2031 self.addCleanup(s.close)
2032 self.assertEqual(0, s.connect_ex(self.server_addr))
2033 self.assertTrue(s.getpeercert())
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002034
2035 def test_non_blocking_connect_ex(self):
2036 # Issue #11326: non-blocking connect_ex() should allow handshake
2037 # to proceed after the socket gets ready.
Christian Heimesd0486372016-09-10 23:23:33 +02002038 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002039 cert_reqs=ssl.CERT_REQUIRED,
2040 ca_certs=SIGNING_CA,
2041 do_handshake_on_connect=False)
2042 self.addCleanup(s.close)
2043 s.setblocking(False)
2044 rc = s.connect_ex(self.server_addr)
2045 # EWOULDBLOCK under Windows, EINPROGRESS elsewhere
2046 self.assertIn(rc, (0, errno.EINPROGRESS, errno.EWOULDBLOCK))
2047 # Wait for connect to finish
2048 select.select([], [s], [], 5.0)
2049 # Non-blocking handshake
2050 while True:
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002051 try:
Martin Panter3840b2a2016-03-27 01:53:46 +00002052 s.do_handshake()
2053 break
2054 except ssl.SSLWantReadError:
2055 select.select([s], [], [], 5.0)
2056 except ssl.SSLWantWriteError:
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002057 select.select([], [s], [], 5.0)
Martin Panter3840b2a2016-03-27 01:53:46 +00002058 # SSL established
2059 self.assertTrue(s.getpeercert())
Antoine Pitrou40f12ab2012-12-28 19:03:43 +01002060
Antoine Pitrou152efa22010-05-16 18:19:27 +00002061 def test_connect_with_context(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002062 # Same as test_connect, but with a separately created context
Christian Heimes2875c602021-04-19 07:27:10 +02002063 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2064 ctx.check_hostname = False
2065 ctx.verify_mode = ssl.CERT_NONE
Martin Panter3840b2a2016-03-27 01:53:46 +00002066 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2067 s.connect(self.server_addr)
2068 self.assertEqual({}, s.getpeercert())
2069 # Same with a server hostname
2070 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2071 server_hostname="dummy") as s:
2072 s.connect(self.server_addr)
2073 ctx.verify_mode = ssl.CERT_REQUIRED
2074 # This should succeed because we specify the root cert
2075 ctx.load_verify_locations(SIGNING_CA)
2076 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2077 s.connect(self.server_addr)
2078 cert = s.getpeercert()
2079 self.assertTrue(cert)
2080
2081 def test_connect_with_context_fail(self):
2082 # This should fail because we have no verification certs. Connection
2083 # failure crashes ThreadedEchoServer, so run this in an independent
2084 # test method.
Christian Heimes2875c602021-04-19 07:27:10 +02002085 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2086 s = ctx.wrap_socket(
2087 socket.socket(socket.AF_INET),
2088 server_hostname=SIGNED_CERTFILE_HOSTNAME
2089 )
Martin Panter3840b2a2016-03-27 01:53:46 +00002090 self.addCleanup(s.close)
2091 self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
2092 s.connect, self.server_addr)
Antoine Pitrou152efa22010-05-16 18:19:27 +00002093
2094 def test_connect_capath(self):
2095 # Verify server certificates using the `capath` argument
Antoine Pitrou467f28d2010-05-16 19:22:44 +00002096 # NOTE: the subject hashing algorithm has been changed between
2097 # OpenSSL 0.9.8n and 1.0.0, as a result the capath directory must
2098 # contain both versions of each certificate (same content, different
Antoine Pitroud7e4c1c2010-05-17 14:13:10 +00002099 # filename) for this test to be portable across OpenSSL releases.
Christian Heimes2875c602021-04-19 07:27:10 +02002100 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002101 ctx.load_verify_locations(capath=CAPATH)
Christian Heimes2875c602021-04-19 07:27:10 +02002102 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2103 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002104 s.connect(self.server_addr)
2105 cert = s.getpeercert()
2106 self.assertTrue(cert)
Christian Heimes529525f2018-05-23 22:24:45 +02002107
Martin Panter3840b2a2016-03-27 01:53:46 +00002108 # Same with a bytes `capath` argument
Christian Heimes2875c602021-04-19 07:27:10 +02002109 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002110 ctx.load_verify_locations(capath=BYTES_CAPATH)
Christian Heimes2875c602021-04-19 07:27:10 +02002111 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2112 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002113 s.connect(self.server_addr)
2114 cert = s.getpeercert()
2115 self.assertTrue(cert)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002116
Christian Heimesefff7062013-11-21 03:35:02 +01002117 def test_connect_cadata(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002118 with open(SIGNING_CA) as f:
Christian Heimesefff7062013-11-21 03:35:02 +01002119 pem = f.read()
2120 der = ssl.PEM_cert_to_DER_cert(pem)
Christian Heimes2875c602021-04-19 07:27:10 +02002121 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002122 ctx.load_verify_locations(cadata=pem)
Christian Heimes2875c602021-04-19 07:27:10 +02002123 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2124 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002125 s.connect(self.server_addr)
2126 cert = s.getpeercert()
2127 self.assertTrue(cert)
Christian Heimesefff7062013-11-21 03:35:02 +01002128
Martin Panter3840b2a2016-03-27 01:53:46 +00002129 # same with DER
Christian Heimes2875c602021-04-19 07:27:10 +02002130 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002131 ctx.load_verify_locations(cadata=der)
Christian Heimes2875c602021-04-19 07:27:10 +02002132 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2133 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002134 s.connect(self.server_addr)
2135 cert = s.getpeercert()
2136 self.assertTrue(cert)
Christian Heimesefff7062013-11-21 03:35:02 +01002137
Antoine Pitroue3220242010-04-24 11:13:53 +00002138 @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
2139 def test_makefile_close(self):
2140 # Issue #5238: creating a file-like object with makefile() shouldn't
2141 # delay closing the underlying "real socket" (here tested with its
2142 # file descriptor, hence skipping the test under Windows).
Christian Heimesd0486372016-09-10 23:23:33 +02002143 ss = test_wrap_socket(socket.socket(socket.AF_INET))
Martin Panter3840b2a2016-03-27 01:53:46 +00002144 ss.connect(self.server_addr)
2145 fd = ss.fileno()
2146 f = ss.makefile()
2147 f.close()
2148 # The fd is still open
2149 os.read(fd, 0)
2150 # Closing the SSL socket should close the fd too
2151 ss.close()
2152 gc.collect()
2153 with self.assertRaises(OSError) as e:
Antoine Pitroue3220242010-04-24 11:13:53 +00002154 os.read(fd, 0)
Martin Panter3840b2a2016-03-27 01:53:46 +00002155 self.assertEqual(e.exception.errno, errno.EBADF)
Antoine Pitroue3220242010-04-24 11:13:53 +00002156
Antoine Pitrou480a1242010-04-28 21:37:09 +00002157 def test_non_blocking_handshake(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002158 s = socket.socket(socket.AF_INET)
2159 s.connect(self.server_addr)
2160 s.setblocking(False)
Christian Heimesd0486372016-09-10 23:23:33 +02002161 s = test_wrap_socket(s,
Martin Panter3840b2a2016-03-27 01:53:46 +00002162 cert_reqs=ssl.CERT_NONE,
2163 do_handshake_on_connect=False)
2164 self.addCleanup(s.close)
2165 count = 0
2166 while True:
2167 try:
2168 count += 1
2169 s.do_handshake()
2170 break
2171 except ssl.SSLWantReadError:
2172 select.select([s], [], [])
2173 except ssl.SSLWantWriteError:
2174 select.select([], [s], [])
2175 if support.verbose:
2176 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002177
Antoine Pitrou480a1242010-04-28 21:37:09 +00002178 def test_get_server_certificate(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002179 _test_get_server_certificate(self, *self.server_addr, cert=SIGNING_CA)
Antoine Pitrou5aefa662011-04-28 19:24:46 +02002180
juhovh49fdf112021-04-18 21:11:48 +10002181 def test_get_server_certificate_sni(self):
2182 host, port = self.server_addr
2183 server_names = []
2184
2185 # We store servername_cb arguments to make sure they match the host
2186 def servername_cb(ssl_sock, server_name, initial_context):
2187 server_names.append(server_name)
2188 self.server_context.set_servername_callback(servername_cb)
2189
2190 pem = ssl.get_server_certificate((host, port))
2191 if not pem:
2192 self.fail("No server certificate on %s:%s!" % (host, port))
2193
2194 pem = ssl.get_server_certificate((host, port), ca_certs=SIGNING_CA)
2195 if not pem:
2196 self.fail("No server certificate on %s:%s!" % (host, port))
2197 if support.verbose:
2198 sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port, pem))
2199
2200 self.assertEqual(server_names, [host, host])
2201
Martin Panter3840b2a2016-03-27 01:53:46 +00002202 def test_get_server_certificate_fail(self):
2203 # Connection failure crashes ThreadedEchoServer, so run this in an
2204 # independent test method
2205 _test_get_server_certificate_fail(self, *self.server_addr)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002206
Zackery Spytzb2fac1a2021-04-23 22:46:01 -06002207 def test_get_server_certificate_timeout(self):
Christian Heimesf05c2ae2021-04-24 07:54:08 +02002208 def servername_cb(ssl_sock, server_name, initial_context):
2209 time.sleep(0.2)
2210 self.server_context.set_servername_callback(servername_cb)
2211
Zackery Spytzb2fac1a2021-04-23 22:46:01 -06002212 with self.assertRaises(socket.timeout):
2213 ssl.get_server_certificate(self.server_addr, ca_certs=SIGNING_CA,
Christian Heimesf05c2ae2021-04-24 07:54:08 +02002214 timeout=0.1)
Zackery Spytzb2fac1a2021-04-23 22:46:01 -06002215
Antoine Pitrouf4c7bad2010-08-15 23:02:22 +00002216 def test_ciphers(self):
Christian Heimesd0486372016-09-10 23:23:33 +02002217 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002218 cert_reqs=ssl.CERT_NONE, ciphers="ALL") as s:
2219 s.connect(self.server_addr)
Christian Heimesd0486372016-09-10 23:23:33 +02002220 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002221 cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT") as s:
2222 s.connect(self.server_addr)
2223 # Error checking can happen at instantiation or when connecting
2224 with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
2225 with socket.socket(socket.AF_INET) as sock:
Christian Heimesd0486372016-09-10 23:23:33 +02002226 s = test_wrap_socket(sock,
Martin Panter3840b2a2016-03-27 01:53:46 +00002227 cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
2228 s.connect(self.server_addr)
Antoine Pitroufec12ff2010-04-21 19:46:23 +00002229
Christian Heimes9a5395a2013-06-17 15:44:12 +02002230 def test_get_ca_certs_capath(self):
2231 # capath certs are loaded on request
Christian Heimesa170fa12017-09-15 20:27:30 +02002232 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002233 ctx.load_verify_locations(capath=CAPATH)
2234 self.assertEqual(ctx.get_ca_certs(), [])
Christian Heimesa170fa12017-09-15 20:27:30 +02002235 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2236 server_hostname='localhost') as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002237 s.connect(self.server_addr)
2238 cert = s.getpeercert()
2239 self.assertTrue(cert)
2240 self.assertEqual(len(ctx.get_ca_certs()), 1)
Christian Heimes9a5395a2013-06-17 15:44:12 +02002241
Christian Heimes8e7f3942013-12-05 07:41:08 +01002242 def test_context_setget(self):
2243 # Check that the context of a connected socket can be replaced.
Christian Heimesa170fa12017-09-15 20:27:30 +02002244 ctx1 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2245 ctx1.load_verify_locations(capath=CAPATH)
2246 ctx2 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2247 ctx2.load_verify_locations(capath=CAPATH)
Martin Panter3840b2a2016-03-27 01:53:46 +00002248 s = socket.socket(socket.AF_INET)
Christian Heimesa170fa12017-09-15 20:27:30 +02002249 with ctx1.wrap_socket(s, server_hostname='localhost') as ss:
Martin Panter3840b2a2016-03-27 01:53:46 +00002250 ss.connect(self.server_addr)
2251 self.assertIs(ss.context, ctx1)
2252 self.assertIs(ss._sslobj.context, ctx1)
2253 ss.context = ctx2
2254 self.assertIs(ss.context, ctx2)
2255 self.assertIs(ss._sslobj.context, ctx2)
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002256
2257 def ssl_io_loop(self, sock, incoming, outgoing, func, *args, **kwargs):
2258 # A simple IO loop. Call func(*args) depending on the error we get
2259 # (WANT_READ or WANT_WRITE) move data between the socket and the BIOs.
Victor Stinner0d63bac2019-12-11 11:30:03 +01002260 timeout = kwargs.get('timeout', support.SHORT_TIMEOUT)
Victor Stinner50a72af2017-09-11 09:34:24 -07002261 deadline = time.monotonic() + timeout
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002262 count = 0
2263 while True:
Victor Stinner50a72af2017-09-11 09:34:24 -07002264 if time.monotonic() > deadline:
2265 self.fail("timeout")
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002266 errno = None
2267 count += 1
2268 try:
2269 ret = func(*args)
2270 except ssl.SSLError as e:
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002271 if e.errno not in (ssl.SSL_ERROR_WANT_READ,
Martin Panter40b97ec2016-01-14 13:05:46 +00002272 ssl.SSL_ERROR_WANT_WRITE):
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002273 raise
2274 errno = e.errno
2275 # Get any data from the outgoing BIO irrespective of any error, and
2276 # send it to the socket.
2277 buf = outgoing.read()
2278 sock.sendall(buf)
2279 # If there's no error, we're done. For WANT_READ, we need to get
2280 # data from the socket and put it in the incoming BIO.
2281 if errno is None:
2282 break
2283 elif errno == ssl.SSL_ERROR_WANT_READ:
2284 buf = sock.recv(32768)
2285 if buf:
2286 incoming.write(buf)
2287 else:
2288 incoming.write_eof()
2289 if support.verbose:
2290 sys.stdout.write("Needed %d calls to complete %s().\n"
2291 % (count, func.__name__))
2292 return ret
2293
Martin Panter3840b2a2016-03-27 01:53:46 +00002294 def test_bio_handshake(self):
2295 sock = socket.socket(socket.AF_INET)
2296 self.addCleanup(sock.close)
2297 sock.connect(self.server_addr)
2298 incoming = ssl.MemoryBIO()
2299 outgoing = ssl.MemoryBIO()
Christian Heimesa170fa12017-09-15 20:27:30 +02002300 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2301 self.assertTrue(ctx.check_hostname)
2302 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Martin Panter3840b2a2016-03-27 01:53:46 +00002303 ctx.load_verify_locations(SIGNING_CA)
Christian Heimesa170fa12017-09-15 20:27:30 +02002304 sslobj = ctx.wrap_bio(incoming, outgoing, False,
2305 SIGNED_CERTFILE_HOSTNAME)
Martin Panter3840b2a2016-03-27 01:53:46 +00002306 self.assertIs(sslobj._sslobj.owner, sslobj)
2307 self.assertIsNone(sslobj.cipher())
Christian Heimes68771112017-09-05 21:55:40 -07002308 self.assertIsNone(sslobj.version())
Christian Heimes01113fa2016-09-05 23:23:24 +02002309 self.assertIsNotNone(sslobj.shared_ciphers())
Martin Panter3840b2a2016-03-27 01:53:46 +00002310 self.assertRaises(ValueError, sslobj.getpeercert)
2311 if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
2312 self.assertIsNone(sslobj.get_channel_binding('tls-unique'))
2313 self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
2314 self.assertTrue(sslobj.cipher())
Christian Heimes01113fa2016-09-05 23:23:24 +02002315 self.assertIsNotNone(sslobj.shared_ciphers())
Christian Heimes68771112017-09-05 21:55:40 -07002316 self.assertIsNotNone(sslobj.version())
Martin Panter3840b2a2016-03-27 01:53:46 +00002317 self.assertTrue(sslobj.getpeercert())
2318 if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
2319 self.assertTrue(sslobj.get_channel_binding('tls-unique'))
2320 try:
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002321 self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
Martin Panter3840b2a2016-03-27 01:53:46 +00002322 except ssl.SSLSyscallError:
2323 # If the server shuts down the TCP connection without sending a
2324 # secure shutdown message, this is reported as SSL_ERROR_SYSCALL
2325 pass
2326 self.assertRaises(ssl.SSLError, sslobj.write, b'foo')
2327
2328 def test_bio_read_write_data(self):
2329 sock = socket.socket(socket.AF_INET)
2330 self.addCleanup(sock.close)
2331 sock.connect(self.server_addr)
2332 incoming = ssl.MemoryBIO()
2333 outgoing = ssl.MemoryBIO()
Christian Heimes2875c602021-04-19 07:27:10 +02002334 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2335 ctx.check_hostname = False
Martin Panter3840b2a2016-03-27 01:53:46 +00002336 ctx.verify_mode = ssl.CERT_NONE
2337 sslobj = ctx.wrap_bio(incoming, outgoing, False)
2338 self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
2339 req = b'FOO\n'
2340 self.ssl_io_loop(sock, incoming, outgoing, sslobj.write, req)
2341 buf = self.ssl_io_loop(sock, incoming, outgoing, sslobj.read, 1024)
2342 self.assertEqual(buf, b'foo\n')
2343 self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002344
2345
Martin Panter3840b2a2016-03-27 01:53:46 +00002346class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002347
Martin Panter3840b2a2016-03-27 01:53:46 +00002348 def test_timeout_connect_ex(self):
2349 # Issue #12065: on a timeout, connect_ex() should return the original
2350 # errno (mimicking the behaviour of non-SSL sockets).
Serhiy Storchakabfb1cf42020-04-29 10:36:20 +03002351 with socket_helper.transient_internet(REMOTE_HOST):
Christian Heimesd0486372016-09-10 23:23:33 +02002352 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002353 cert_reqs=ssl.CERT_REQUIRED,
2354 do_handshake_on_connect=False)
2355 self.addCleanup(s.close)
2356 s.settimeout(0.0000001)
2357 rc = s.connect_ex((REMOTE_HOST, 443))
2358 if rc == 0:
2359 self.skipTest("REMOTE_HOST responded too quickly")
Carl Meyer29c451c2021-03-27 15:52:28 -06002360 elif rc == errno.ENETUNREACH:
2361 self.skipTest("Network unreachable.")
Martin Panter3840b2a2016-03-27 01:53:46 +00002362 self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK))
2363
Serhiy Storchaka16994912020-04-25 10:06:29 +03002364 @unittest.skipUnless(socket_helper.IPV6_ENABLED, 'Needs IPv6')
Martin Panter3840b2a2016-03-27 01:53:46 +00002365 def test_get_server_certificate_ipv6(self):
Serhiy Storchakabfb1cf42020-04-29 10:36:20 +03002366 with socket_helper.transient_internet('ipv6.google.com'):
Martin Panter3840b2a2016-03-27 01:53:46 +00002367 _test_get_server_certificate(self, 'ipv6.google.com', 443)
2368 _test_get_server_certificate_fail(self, 'ipv6.google.com', 443)
2369
Martin Panter3840b2a2016-03-27 01:53:46 +00002370
2371def _test_get_server_certificate(test, host, port, cert=None):
2372 pem = ssl.get_server_certificate((host, port))
2373 if not pem:
2374 test.fail("No server certificate on %s:%s!" % (host, port))
2375
2376 pem = ssl.get_server_certificate((host, port), ca_certs=cert)
2377 if not pem:
2378 test.fail("No server certificate on %s:%s!" % (host, port))
2379 if support.verbose:
2380 sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem))
2381
2382def _test_get_server_certificate_fail(test, host, port):
2383 try:
2384 pem = ssl.get_server_certificate((host, port), ca_certs=CERTFILE)
2385 except ssl.SSLError as x:
2386 #should fail
2387 if support.verbose:
2388 sys.stdout.write("%s\n" % x)
2389 else:
2390 test.fail("Got server certificate %s for %s:%s!" % (pem, host, port))
2391
2392
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002393from test.ssl_servers import make_https_server
Antoine Pitrou803e6d62010-10-13 10:36:15 +00002394
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002395class ThreadedEchoServer(threading.Thread):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002396
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002397 class ConnectionHandler(threading.Thread):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002398
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002399 """A mildly complicated class, because we want it to work both
2400 with and without the SSL wrapper around the socket connection, so
2401 that we can test the STARTTLS functionality."""
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002402
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002403 def __init__(self, server, connsock, addr):
2404 self.server = server
2405 self.running = False
2406 self.sock = connsock
2407 self.addr = addr
Serhiy Storchaka5eca7f32019-09-01 12:12:52 +03002408 self.sock.setblocking(True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002409 self.sslconn = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002410 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +00002411 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002412
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002413 def wrap_conn(self):
2414 try:
2415 self.sslconn = self.server.context.wrap_socket(
2416 self.sock, server_side=True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002417 self.server.selected_alpn_protocols.append(self.sslconn.selected_alpn_protocol())
Paul Monsonfb7e7502019-05-15 15:38:55 -07002418 except (ConnectionResetError, BrokenPipeError, ConnectionAbortedError) as e:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002419 # We treat ConnectionResetError as though it were an
2420 # SSLError - OpenSSL on Ubuntu abruptly closes the
2421 # connection when asked to use an unsupported protocol.
2422 #
Christian Heimes529525f2018-05-23 22:24:45 +02002423 # BrokenPipeError is raised in TLS 1.3 mode, when OpenSSL
2424 # tries to send session tickets after handshake.
2425 # https://github.com/openssl/openssl/issues/6342
Paul Monsonfb7e7502019-05-15 15:38:55 -07002426 #
2427 # ConnectionAbortedError is raised in TLS 1.3 mode, when OpenSSL
2428 # tries to send session tickets after handshake when using WinSock.
Christian Heimes529525f2018-05-23 22:24:45 +02002429 self.server.conn_errors.append(str(e))
2430 if self.server.chatty:
2431 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
2432 self.running = False
2433 self.close()
2434 return False
2435 except (ssl.SSLError, OSError) as e:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002436 # OSError may occur with wrong protocols, e.g. both
2437 # sides use PROTOCOL_TLS_SERVER.
2438 #
2439 # XXX Various errors can have happened here, for example
2440 # a mismatching protocol version, an invalid certificate,
2441 # or a low-level bug. This should be made more discriminating.
2442 #
2443 # bpo-31323: Store the exception as string to prevent
2444 # a reference leak: server -> conn_errors -> exception
2445 # -> traceback -> self (ConnectionHandler) -> server
2446 self.server.conn_errors.append(str(e))
2447 if self.server.chatty:
2448 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Miss Islington (bot)b3fac2922021-06-24 05:27:35 -07002449
2450 # bpo-44229, bpo-43855, bpo-44237, and bpo-33450:
2451 # Ignore spurious EPROTOTYPE returned by write() on macOS.
2452 # See also http://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/
2453 if e.errno != errno.EPROTOTYPE and sys.platform != "darwin":
2454 self.running = False
2455 self.server.stop()
2456 self.close()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002457 return False
2458 else:
2459 self.server.shared_ciphers.append(self.sslconn.shared_ciphers())
2460 if self.server.context.verify_mode == ssl.CERT_REQUIRED:
2461 cert = self.sslconn.getpeercert()
2462 if support.verbose and self.server.chatty:
2463 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
2464 cert_binary = self.sslconn.getpeercert(True)
2465 if support.verbose and self.server.chatty:
Christian Heimesc8666cf2021-04-24 09:17:54 +02002466 if cert_binary is None:
2467 sys.stdout.write(" client did not provide a cert\n")
2468 else:
2469 sys.stdout.write(f" cert binary is {len(cert_binary)}b\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002470 cipher = self.sslconn.cipher()
2471 if support.verbose and self.server.chatty:
2472 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002473 return True
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002474
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002475 def read(self):
2476 if self.sslconn:
2477 return self.sslconn.read()
2478 else:
2479 return self.sock.recv(1024)
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002480
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002481 def write(self, bytes):
2482 if self.sslconn:
2483 return self.sslconn.write(bytes)
2484 else:
2485 return self.sock.send(bytes)
2486
2487 def close(self):
2488 if self.sslconn:
2489 self.sslconn.close()
2490 else:
2491 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002492
Antoine Pitrou480a1242010-04-28 21:37:09 +00002493 def run(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002494 self.running = True
2495 if not self.server.starttls_server:
2496 if not self.wrap_conn():
2497 return
2498 while self.running:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002499 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002500 msg = self.read()
2501 stripped = msg.strip()
2502 if not stripped:
2503 # eof, so quit this handler
2504 self.running = False
2505 try:
2506 self.sock = self.sslconn.unwrap()
2507 except OSError:
2508 # Many tests shut the TCP connection down
2509 # without an SSL shutdown. This causes
2510 # unwrap() to raise OSError with errno=0!
2511 pass
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00002512 else:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002513 self.sslconn = None
2514 self.close()
2515 elif stripped == b'over':
2516 if support.verbose and self.server.connectionchatty:
2517 sys.stdout.write(" server: client closed connection\n")
2518 self.close()
2519 return
2520 elif (self.server.starttls_server and
2521 stripped == b'STARTTLS'):
2522 if support.verbose and self.server.connectionchatty:
2523 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
2524 self.write(b"OK\n")
2525 if not self.wrap_conn():
2526 return
2527 elif (self.server.starttls_server and self.sslconn
2528 and stripped == b'ENDTLS'):
2529 if support.verbose and self.server.connectionchatty:
2530 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
2531 self.write(b"OK\n")
2532 self.sock = self.sslconn.unwrap()
2533 self.sslconn = None
2534 if support.verbose and self.server.connectionchatty:
2535 sys.stdout.write(" server: connection is now unencrypted...\n")
2536 elif stripped == b'CB tls-unique':
2537 if support.verbose and self.server.connectionchatty:
2538 sys.stdout.write(" server: read CB tls-unique from client, sending our CB data...\n")
2539 data = self.sslconn.get_channel_binding("tls-unique")
2540 self.write(repr(data).encode("us-ascii") + b"\n")
Christian Heimes9fb051f2018-09-23 08:32:31 +02002541 elif stripped == b'PHA':
2542 if support.verbose and self.server.connectionchatty:
2543 sys.stdout.write(" server: initiating post handshake auth\n")
2544 try:
2545 self.sslconn.verify_client_post_handshake()
2546 except ssl.SSLError as e:
2547 self.write(repr(e).encode("us-ascii") + b"\n")
2548 else:
2549 self.write(b"OK\n")
2550 elif stripped == b'HASCERT':
2551 if self.sslconn.getpeercert() is not None:
2552 self.write(b'TRUE\n')
2553 else:
2554 self.write(b'FALSE\n')
2555 elif stripped == b'GETCERT':
2556 cert = self.sslconn.getpeercert()
2557 self.write(repr(cert).encode("us-ascii") + b"\n")
Christian Heimes666991f2021-04-26 15:01:40 +02002558 elif stripped == b'VERIFIEDCHAIN':
2559 certs = self.sslconn._sslobj.get_verified_chain()
2560 self.write(len(certs).to_bytes(1, "big") + b"\n")
2561 elif stripped == b'UNVERIFIEDCHAIN':
2562 certs = self.sslconn._sslobj.get_unverified_chain()
2563 self.write(len(certs).to_bytes(1, "big") + b"\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002564 else:
2565 if (support.verbose and
2566 self.server.connectionchatty):
2567 ctype = (self.sslconn and "encrypted") or "unencrypted"
2568 sys.stdout.write(" server: read %r (%s), sending back %r (%s)...\n"
2569 % (msg, ctype, msg.lower(), ctype))
2570 self.write(msg.lower())
Christian Heimesc8666cf2021-04-24 09:17:54 +02002571 except OSError as e:
2572 # handles SSLError and socket errors
Christian Heimes529525f2018-05-23 22:24:45 +02002573 if self.server.chatty and support.verbose:
Christian Heimesc8666cf2021-04-24 09:17:54 +02002574 if isinstance(e, ConnectionError):
2575 # OpenSSL 1.1.1 sometimes raises
2576 # ConnectionResetError when connection is not
2577 # shut down gracefully.
2578 print(
2579 f" Connection reset by peer: {self.addr}"
2580 )
2581 else:
2582 handle_error("Test server failure:\n")
2583 try:
2584 self.write(b"ERROR\n")
2585 except OSError:
2586 pass
Bill Janssen2f5799b2008-06-29 00:08:12 +00002587 self.close()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002588 self.running = False
Christian Heimes529525f2018-05-23 22:24:45 +02002589
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002590 # normally, we'd just stop here, but for the test
2591 # harness, we want to stop the server
2592 self.server.stop()
Bill Janssen54cc54c2007-12-14 22:08:56 +00002593
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002594 def __init__(self, certificate=None, ssl_version=None,
2595 certreqs=None, cacerts=None,
2596 chatty=True, connectionchatty=False, starttls_server=False,
Christian Heimes2875c602021-04-19 07:27:10 +02002597 alpn_protocols=None,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002598 ciphers=None, context=None):
2599 if context:
2600 self.context = context
2601 else:
2602 self.context = ssl.SSLContext(ssl_version
2603 if ssl_version is not None
Christian Heimesa170fa12017-09-15 20:27:30 +02002604 else ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002605 self.context.verify_mode = (certreqs if certreqs is not None
2606 else ssl.CERT_NONE)
2607 if cacerts:
2608 self.context.load_verify_locations(cacerts)
2609 if certificate:
2610 self.context.load_cert_chain(certificate)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002611 if alpn_protocols:
2612 self.context.set_alpn_protocols(alpn_protocols)
2613 if ciphers:
2614 self.context.set_ciphers(ciphers)
2615 self.chatty = chatty
2616 self.connectionchatty = connectionchatty
2617 self.starttls_server = starttls_server
2618 self.sock = socket.socket()
Serhiy Storchaka16994912020-04-25 10:06:29 +03002619 self.port = socket_helper.bind_port(self.sock)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002620 self.flag = None
2621 self.active = False
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002622 self.selected_alpn_protocols = []
2623 self.shared_ciphers = []
2624 self.conn_errors = []
2625 threading.Thread.__init__(self)
2626 self.daemon = True
2627
2628 def __enter__(self):
2629 self.start(threading.Event())
2630 self.flag.wait()
2631 return self
2632
2633 def __exit__(self, *args):
2634 self.stop()
2635 self.join()
2636
2637 def start(self, flag=None):
2638 self.flag = flag
2639 threading.Thread.start(self)
2640
2641 def run(self):
Christian Heimesc715b522021-05-03 17:45:02 +02002642 self.sock.settimeout(1.0)
2643 self.sock.listen(5)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002644 self.active = True
2645 if self.flag:
2646 # signal an event
2647 self.flag.set()
2648 while self.active:
2649 try:
2650 newconn, connaddr = self.sock.accept()
2651 if support.verbose and self.chatty:
2652 sys.stdout.write(' server: new connection from '
2653 + repr(connaddr) + '\n')
2654 handler = self.ConnectionHandler(self, newconn, connaddr)
2655 handler.start()
2656 handler.join()
Christian Heimesc715b522021-05-03 17:45:02 +02002657 except TimeoutError as e:
2658 if support.verbose:
2659 sys.stdout.write(f' connection timeout {e!r}\n')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002660 except KeyboardInterrupt:
2661 self.stop()
Christian Heimes529525f2018-05-23 22:24:45 +02002662 except BaseException as e:
2663 if support.verbose and self.chatty:
2664 sys.stdout.write(
2665 ' connection handling failed: ' + repr(e) + '\n')
2666
Christian Heimesc715b522021-05-03 17:45:02 +02002667 self.close()
2668
2669 def close(self):
2670 if self.sock is not None:
2671 self.sock.close()
2672 self.sock = None
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002673
2674 def stop(self):
2675 self.active = False
2676
2677class AsyncoreEchoServer(threading.Thread):
2678
2679 # this one's based on asyncore.dispatcher
2680
2681 class EchoServer (asyncore.dispatcher):
2682
2683 class ConnectionHandler(asyncore.dispatcher_with_send):
2684
2685 def __init__(self, conn, certfile):
2686 self.socket = test_wrap_socket(conn, server_side=True,
2687 certfile=certfile,
2688 do_handshake_on_connect=False)
2689 asyncore.dispatcher_with_send.__init__(self, self.socket)
2690 self._ssl_accepting = True
2691 self._do_ssl_handshake()
2692
2693 def readable(self):
2694 if isinstance(self.socket, ssl.SSLSocket):
2695 while self.socket.pending() > 0:
2696 self.handle_read_event()
2697 return True
2698
2699 def _do_ssl_handshake(self):
2700 try:
2701 self.socket.do_handshake()
2702 except (ssl.SSLWantReadError, ssl.SSLWantWriteError):
2703 return
2704 except ssl.SSLEOFError:
2705 return self.handle_close()
2706 except ssl.SSLError:
Bill Janssen54cc54c2007-12-14 22:08:56 +00002707 raise
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002708 except OSError as err:
2709 if err.args[0] == errno.ECONNABORTED:
2710 return self.handle_close()
2711 else:
2712 self._ssl_accepting = False
Bill Janssen54cc54c2007-12-14 22:08:56 +00002713
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002714 def handle_read(self):
2715 if self._ssl_accepting:
2716 self._do_ssl_handshake()
2717 else:
2718 data = self.recv(1024)
2719 if support.verbose:
2720 sys.stdout.write(" server: read %s from client\n" % repr(data))
2721 if not data:
2722 self.close()
2723 else:
2724 self.send(data.lower())
Bill Janssen54cc54c2007-12-14 22:08:56 +00002725
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002726 def handle_close(self):
2727 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002728 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002729 sys.stdout.write(" server: closed connection %s\n" % self.socket)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002730
2731 def handle_error(self):
2732 raise
2733
Trent Nelson78520002008-04-10 20:54:35 +00002734 def __init__(self, certfile):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002735 self.certfile = certfile
2736 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Serhiy Storchaka16994912020-04-25 10:06:29 +03002737 self.port = socket_helper.bind_port(sock, '')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002738 asyncore.dispatcher.__init__(self, sock)
2739 self.listen(5)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002740
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002741 def handle_accepted(self, sock_obj, addr):
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002742 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002743 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
2744 self.ConnectionHandler(sock_obj, self.certfile)
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002745
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002746 def handle_error(self):
2747 raise
Bill Janssen54cc54c2007-12-14 22:08:56 +00002748
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002749 def __init__(self, certfile):
2750 self.flag = None
2751 self.active = False
2752 self.server = self.EchoServer(certfile)
2753 self.port = self.server.port
2754 threading.Thread.__init__(self)
2755 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +00002756
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002757 def __str__(self):
2758 return "<%s %s>" % (self.__class__.__name__, self.server)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002759
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002760 def __enter__(self):
2761 self.start(threading.Event())
2762 self.flag.wait()
2763 return self
Thomas Woutersed03b412007-08-28 21:37:11 +00002764
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002765 def __exit__(self, *args):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002766 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002767 sys.stdout.write(" cleanup: stopping server.\n")
2768 self.stop()
2769 if support.verbose:
2770 sys.stdout.write(" cleanup: joining server thread.\n")
2771 self.join()
2772 if support.verbose:
2773 sys.stdout.write(" cleanup: successfully joined.\n")
2774 # make sure that ConnectionHandler is removed from socket_map
2775 asyncore.close_all(ignore_all=True)
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01002776
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002777 def start (self, flag=None):
2778 self.flag = flag
2779 threading.Thread.start(self)
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01002780
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002781 def run(self):
2782 self.active = True
2783 if self.flag:
2784 self.flag.set()
2785 while self.active:
Antoine Pitrou773b5db2010-04-27 08:53:36 +00002786 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002787 asyncore.loop(1)
2788 except:
2789 pass
Trent Nelson6b240cd2008-04-10 20:12:06 +00002790
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002791 def stop(self):
2792 self.active = False
2793 self.server.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002794
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002795def server_params_test(client_context, server_context, indata=b"FOO\n",
2796 chatty=True, connectionchatty=False, sni_name=None,
2797 session=None):
2798 """
2799 Launch a server, connect a client to it and try various reads
2800 and writes.
2801 """
2802 stats = {}
2803 server = ThreadedEchoServer(context=server_context,
2804 chatty=chatty,
2805 connectionchatty=False)
2806 with server:
2807 with client_context.wrap_socket(socket.socket(),
2808 server_hostname=sni_name, session=session) as s:
2809 s.connect((HOST, server.port))
2810 for arg in [indata, bytearray(indata), memoryview(indata)]:
2811 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002812 if support.verbose:
Antoine Pitrou18c913e2010-04-27 10:59:39 +00002813 sys.stdout.write(
Antoine Pitrou480a1242010-04-28 21:37:09 +00002814 " client: sending %r...\n" % indata)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002815 s.write(arg)
Antoine Pitrou18c913e2010-04-27 10:59:39 +00002816 outdata = s.read()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002817 if connectionchatty:
2818 if support.verbose:
2819 sys.stdout.write(" client: read %r\n" % outdata)
Trent Nelson6b240cd2008-04-10 20:12:06 +00002820 if outdata != indata.lower():
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002821 raise AssertionError(
Antoine Pitrou480a1242010-04-28 21:37:09 +00002822 "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
2823 % (outdata[:20], len(outdata),
2824 indata[:20].lower(), len(indata)))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002825 s.write(b"over\n")
2826 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002827 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00002828 sys.stdout.write(" client: closing connection.\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002829 stats.update({
2830 'compression': s.compression(),
2831 'cipher': s.cipher(),
2832 'peercert': s.getpeercert(),
2833 'client_alpn_protocol': s.selected_alpn_protocol(),
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002834 'version': s.version(),
2835 'session_reused': s.session_reused,
2836 'session': s.session,
2837 })
2838 s.close()
2839 stats['server_alpn_protocols'] = server.selected_alpn_protocols
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002840 stats['server_shared_ciphers'] = server.shared_ciphers
2841 return stats
Trent Nelson6b240cd2008-04-10 20:12:06 +00002842
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002843def try_protocol_combo(server_protocol, client_protocol, expect_success,
2844 certsreqs=None, server_options=0, client_options=0):
2845 """
2846 Try to SSL-connect using *client_protocol* to *server_protocol*.
2847 If *expect_success* is true, assert that the connection succeeds,
2848 if it's false, assert that the connection fails.
2849 Also, if *expect_success* is a string, assert that it is the protocol
2850 version actually used by the connection.
2851 """
2852 if certsreqs is None:
2853 certsreqs = ssl.CERT_NONE
2854 certtype = {
2855 ssl.CERT_NONE: "CERT_NONE",
2856 ssl.CERT_OPTIONAL: "CERT_OPTIONAL",
2857 ssl.CERT_REQUIRED: "CERT_REQUIRED",
2858 }[certsreqs]
2859 if support.verbose:
2860 formatstr = (expect_success and " %s->%s %s\n") or " {%s->%s} %s\n"
2861 sys.stdout.write(formatstr %
2862 (ssl.get_protocol_name(client_protocol),
2863 ssl.get_protocol_name(server_protocol),
2864 certtype))
Christian Heimes2875c602021-04-19 07:27:10 +02002865
2866 with warnings_helper.check_warnings():
2867 # ignore Deprecation warnings
2868 client_context = ssl.SSLContext(client_protocol)
2869 client_context.options |= client_options
2870 server_context = ssl.SSLContext(server_protocol)
2871 server_context.options |= server_options
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002872
Victor Stinner3ef63442019-02-19 18:06:03 +01002873 min_version = PROTOCOL_TO_TLS_VERSION.get(client_protocol, None)
2874 if (min_version is not None
Christian Heimes2875c602021-04-19 07:27:10 +02002875 # SSLContext.minimum_version is only available on recent OpenSSL
2876 # (setter added in OpenSSL 1.1.0, getter added in OpenSSL 1.1.1)
2877 and hasattr(server_context, 'minimum_version')
2878 and server_protocol == ssl.PROTOCOL_TLS
2879 and server_context.minimum_version > min_version
2880 ):
Victor Stinner3ef63442019-02-19 18:06:03 +01002881 # If OpenSSL configuration is strict and requires more recent TLS
2882 # version, we have to change the minimum to test old TLS versions.
Christian Heimes2875c602021-04-19 07:27:10 +02002883 with warnings_helper.check_warnings():
2884 server_context.minimum_version = min_version
Victor Stinner3ef63442019-02-19 18:06:03 +01002885
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002886 # NOTE: we must enable "ALL" ciphers on the client, otherwise an
2887 # SSLv23 client will send an SSLv3 hello (rather than SSLv2)
2888 # starting from OpenSSL 1.0.0 (see issue #8322).
Christian Heimesa170fa12017-09-15 20:27:30 +02002889 if client_context.protocol == ssl.PROTOCOL_TLS:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002890 client_context.set_ciphers("ALL")
2891
Christian Heimesf6c6b582021-03-18 23:06:50 +01002892 seclevel_workaround(server_context, client_context)
2893
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002894 for ctx in (client_context, server_context):
2895 ctx.verify_mode = certsreqs
Christian Heimesbd5c7d22018-01-20 15:16:30 +01002896 ctx.load_cert_chain(SIGNED_CERTFILE)
2897 ctx.load_verify_locations(SIGNING_CA)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002898 try:
2899 stats = server_params_test(client_context, server_context,
2900 chatty=False, connectionchatty=False)
2901 # Protocol mismatch can result in either an SSLError, or a
2902 # "Connection reset by peer" error.
2903 except ssl.SSLError:
2904 if expect_success:
2905 raise
2906 except OSError as e:
2907 if expect_success or e.errno != errno.ECONNRESET:
2908 raise
2909 else:
2910 if not expect_success:
2911 raise AssertionError(
2912 "Client protocol %s succeeded with server protocol %s!"
2913 % (ssl.get_protocol_name(client_protocol),
2914 ssl.get_protocol_name(server_protocol)))
2915 elif (expect_success is not True
2916 and expect_success != stats['version']):
2917 raise AssertionError("version mismatch: expected %r, got %r"
2918 % (expect_success, stats['version']))
2919
2920
2921class ThreadedTests(unittest.TestCase):
2922
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002923 def test_echo(self):
2924 """Basic test of an SSL client connecting to a server"""
2925 if support.verbose:
2926 sys.stdout.write("\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002927
Christian Heimesa170fa12017-09-15 20:27:30 +02002928 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002929
2930 with self.subTest(client=ssl.PROTOCOL_TLS_CLIENT, server=ssl.PROTOCOL_TLS_SERVER):
2931 server_params_test(client_context=client_context,
2932 server_context=server_context,
2933 chatty=True, connectionchatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02002934 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002935
2936 client_context.check_hostname = False
2937 with self.subTest(client=ssl.PROTOCOL_TLS_SERVER, server=ssl.PROTOCOL_TLS_CLIENT):
2938 with self.assertRaises(ssl.SSLError) as e:
2939 server_params_test(client_context=server_context,
2940 server_context=client_context,
2941 chatty=True, connectionchatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02002942 sni_name=hostname)
Miss Islington (bot)d7930fb2021-06-11 00:36:17 -07002943 self.assertIn(
2944 'Cannot create a client socket with a PROTOCOL_TLS_SERVER context',
2945 str(e.exception)
2946 )
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002947
2948 with self.subTest(client=ssl.PROTOCOL_TLS_SERVER, server=ssl.PROTOCOL_TLS_SERVER):
2949 with self.assertRaises(ssl.SSLError) as e:
2950 server_params_test(client_context=server_context,
2951 server_context=server_context,
2952 chatty=True, connectionchatty=True)
Miss Islington (bot)d7930fb2021-06-11 00:36:17 -07002953 self.assertIn(
2954 'Cannot create a client socket with a PROTOCOL_TLS_SERVER context',
2955 str(e.exception)
2956 )
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002957
2958 with self.subTest(client=ssl.PROTOCOL_TLS_CLIENT, server=ssl.PROTOCOL_TLS_CLIENT):
2959 with self.assertRaises(ssl.SSLError) as e:
2960 server_params_test(client_context=server_context,
2961 server_context=client_context,
2962 chatty=True, connectionchatty=True)
Miss Islington (bot)d7930fb2021-06-11 00:36:17 -07002963 self.assertIn(
2964 'Cannot create a client socket with a PROTOCOL_TLS_SERVER context',
2965 str(e.exception))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002966
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002967 def test_getpeercert(self):
2968 if support.verbose:
2969 sys.stdout.write("\n")
Christian Heimesa170fa12017-09-15 20:27:30 +02002970
2971 client_context, server_context, hostname = testing_context()
2972 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002973 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002974 with client_context.wrap_socket(socket.socket(),
2975 do_handshake_on_connect=False,
2976 server_hostname=hostname) as s:
2977 s.connect((HOST, server.port))
2978 # getpeercert() raise ValueError while the handshake isn't
2979 # done.
2980 with self.assertRaises(ValueError):
2981 s.getpeercert()
2982 s.do_handshake()
2983 cert = s.getpeercert()
2984 self.assertTrue(cert, "Can't get peer certificate.")
2985 cipher = s.cipher()
2986 if support.verbose:
2987 sys.stdout.write(pprint.pformat(cert) + '\n')
2988 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
2989 if 'subject' not in cert:
2990 self.fail("No subject field in certificate: %s." %
2991 pprint.pformat(cert))
2992 if ((('organizationName', 'Python Software Foundation'),)
2993 not in cert['subject']):
2994 self.fail(
2995 "Missing or invalid 'organizationName' field in certificate subject; "
2996 "should be 'Python Software Foundation'.")
2997 self.assertIn('notBefore', cert)
2998 self.assertIn('notAfter', cert)
2999 before = ssl.cert_time_to_seconds(cert['notBefore'])
3000 after = ssl.cert_time_to_seconds(cert['notAfter'])
3001 self.assertLess(before, after)
Bill Janssen58afe4c2008-09-08 16:45:19 +00003002
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003003 def test_crl_check(self):
3004 if support.verbose:
3005 sys.stdout.write("\n")
3006
Christian Heimesa170fa12017-09-15 20:27:30 +02003007 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003008
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003009 tf = getattr(ssl, "VERIFY_X509_TRUSTED_FIRST", 0)
Christian Heimesa170fa12017-09-15 20:27:30 +02003010 self.assertEqual(client_context.verify_flags, ssl.VERIFY_DEFAULT | tf)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003011
3012 # VERIFY_DEFAULT should pass
3013 server = ThreadedEchoServer(context=server_context, chatty=True)
3014 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02003015 with client_context.wrap_socket(socket.socket(),
3016 server_hostname=hostname) as s:
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01003017 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003018 cert = s.getpeercert()
3019 self.assertTrue(cert, "Can't get peer certificate.")
Bill Janssen58afe4c2008-09-08 16:45:19 +00003020
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003021 # VERIFY_CRL_CHECK_LEAF without a loaded CRL file fails
Christian Heimesa170fa12017-09-15 20:27:30 +02003022 client_context.verify_flags |= ssl.VERIFY_CRL_CHECK_LEAF
Bill Janssen58afe4c2008-09-08 16:45:19 +00003023
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003024 server = ThreadedEchoServer(context=server_context, chatty=True)
3025 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02003026 with client_context.wrap_socket(socket.socket(),
3027 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003028 with self.assertRaisesRegex(ssl.SSLError,
3029 "certificate verify failed"):
3030 s.connect((HOST, server.port))
Bill Janssen58afe4c2008-09-08 16:45:19 +00003031
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003032 # now load a CRL file. The CRL file is signed by the CA.
Christian Heimesa170fa12017-09-15 20:27:30 +02003033 client_context.load_verify_locations(CRLFILE)
Bill Janssen58afe4c2008-09-08 16:45:19 +00003034
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003035 server = ThreadedEchoServer(context=server_context, chatty=True)
3036 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02003037 with client_context.wrap_socket(socket.socket(),
3038 server_hostname=hostname) as s:
Antoine Pitroub4bebda2014-04-29 10:03:28 +02003039 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003040 cert = s.getpeercert()
3041 self.assertTrue(cert, "Can't get peer certificate.")
Antoine Pitroub4bebda2014-04-29 10:03:28 +02003042
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003043 def test_check_hostname(self):
3044 if support.verbose:
3045 sys.stdout.write("\n")
Antoine Pitroub4bebda2014-04-29 10:03:28 +02003046
Christian Heimesa170fa12017-09-15 20:27:30 +02003047 client_context, server_context, hostname = testing_context()
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003048
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003049 # correct hostname should verify
3050 server = ThreadedEchoServer(context=server_context, chatty=True)
3051 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02003052 with client_context.wrap_socket(socket.socket(),
3053 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003054 s.connect((HOST, server.port))
3055 cert = s.getpeercert()
3056 self.assertTrue(cert, "Can't get peer certificate.")
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003057
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003058 # incorrect hostname should raise an exception
3059 server = ThreadedEchoServer(context=server_context, chatty=True)
3060 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02003061 with client_context.wrap_socket(socket.socket(),
3062 server_hostname="invalid") as s:
Christian Heimes61d478c2018-01-27 15:51:38 +01003063 with self.assertRaisesRegex(
3064 ssl.CertificateError,
3065 "Hostname mismatch, certificate is not valid for 'invalid'."):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003066 s.connect((HOST, server.port))
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003067
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003068 # missing server_hostname arg should cause an exception, too
3069 server = ThreadedEchoServer(context=server_context, chatty=True)
3070 with server:
3071 with socket.socket() as s:
3072 with self.assertRaisesRegex(ValueError,
3073 "check_hostname requires server_hostname"):
Christian Heimesa170fa12017-09-15 20:27:30 +02003074 client_context.wrap_socket(s)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003075
Christian Heimesb467d9a2021-04-17 10:07:19 +02003076 @unittest.skipUnless(
3077 ssl.HAS_NEVER_CHECK_COMMON_NAME, "test requires hostname_checks_common_name"
3078 )
3079 def test_hostname_checks_common_name(self):
3080 client_context, server_context, hostname = testing_context()
3081 assert client_context.hostname_checks_common_name
3082 client_context.hostname_checks_common_name = False
3083
3084 # default cert has a SAN
3085 server = ThreadedEchoServer(context=server_context, chatty=True)
3086 with server:
3087 with client_context.wrap_socket(socket.socket(),
3088 server_hostname=hostname) as s:
3089 s.connect((HOST, server.port))
3090
3091 client_context, server_context, hostname = testing_context(NOSANFILE)
3092 client_context.hostname_checks_common_name = False
3093 server = ThreadedEchoServer(context=server_context, chatty=True)
3094 with server:
3095 with client_context.wrap_socket(socket.socket(),
3096 server_hostname=hostname) as s:
3097 with self.assertRaises(ssl.SSLCertVerificationError):
3098 s.connect((HOST, server.port))
3099
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003100 def test_ecc_cert(self):
3101 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3102 client_context.load_verify_locations(SIGNING_CA)
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003103 client_context.set_ciphers('ECDHE:ECDSA:!NULL:!aRSA')
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003104 hostname = SIGNED_CERTFILE_ECC_HOSTNAME
3105
3106 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3107 # load ECC cert
3108 server_context.load_cert_chain(SIGNED_CERTFILE_ECC)
3109
3110 # correct hostname should verify
3111 server = ThreadedEchoServer(context=server_context, chatty=True)
3112 with server:
3113 with client_context.wrap_socket(socket.socket(),
3114 server_hostname=hostname) as s:
3115 s.connect((HOST, server.port))
3116 cert = s.getpeercert()
3117 self.assertTrue(cert, "Can't get peer certificate.")
3118 cipher = s.cipher()[0].split('-')
3119 self.assertTrue(cipher[:2], ('ECDHE', 'ECDSA'))
3120
3121 def test_dual_rsa_ecc(self):
3122 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3123 client_context.load_verify_locations(SIGNING_CA)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003124 # TODO: fix TLSv1.3 once SSLContext can restrict signature
3125 # algorithms.
Miss Islington (bot)4becc562021-06-13 05:07:00 -07003126 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003127 # only ECDSA certs
3128 client_context.set_ciphers('ECDHE:ECDSA:!NULL:!aRSA')
3129 hostname = SIGNED_CERTFILE_ECC_HOSTNAME
3130
3131 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3132 # load ECC and RSA key/cert pairs
3133 server_context.load_cert_chain(SIGNED_CERTFILE_ECC)
3134 server_context.load_cert_chain(SIGNED_CERTFILE)
3135
3136 # correct hostname should verify
3137 server = ThreadedEchoServer(context=server_context, chatty=True)
3138 with server:
3139 with client_context.wrap_socket(socket.socket(),
3140 server_hostname=hostname) as s:
3141 s.connect((HOST, server.port))
3142 cert = s.getpeercert()
3143 self.assertTrue(cert, "Can't get peer certificate.")
3144 cipher = s.cipher()[0].split('-')
3145 self.assertTrue(cipher[:2], ('ECDHE', 'ECDSA'))
3146
Christian Heimes66e57422018-01-29 14:25:13 +01003147 def test_check_hostname_idn(self):
3148 if support.verbose:
3149 sys.stdout.write("\n")
3150
Christian Heimes11a14932018-02-24 02:35:08 +01003151 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimes66e57422018-01-29 14:25:13 +01003152 server_context.load_cert_chain(IDNSANSFILE)
3153
Christian Heimes11a14932018-02-24 02:35:08 +01003154 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes66e57422018-01-29 14:25:13 +01003155 context.verify_mode = ssl.CERT_REQUIRED
3156 context.check_hostname = True
3157 context.load_verify_locations(SIGNING_CA)
3158
3159 # correct hostname should verify, when specified in several
3160 # different ways
3161 idn_hostnames = [
3162 ('könig.idn.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003163 'xn--knig-5qa.idn.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003164 ('xn--knig-5qa.idn.pythontest.net',
3165 'xn--knig-5qa.idn.pythontest.net'),
3166 (b'xn--knig-5qa.idn.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003167 'xn--knig-5qa.idn.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003168
3169 ('königsgäßchen.idna2003.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003170 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003171 ('xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
3172 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
3173 (b'xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003174 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
3175
3176 # ('königsgäßchen.idna2008.pythontest.net',
3177 # 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3178 ('xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
3179 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3180 (b'xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
3181 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3182
Christian Heimes66e57422018-01-29 14:25:13 +01003183 ]
3184 for server_hostname, expected_hostname in idn_hostnames:
3185 server = ThreadedEchoServer(context=server_context, chatty=True)
3186 with server:
3187 with context.wrap_socket(socket.socket(),
3188 server_hostname=server_hostname) as s:
3189 self.assertEqual(s.server_hostname, expected_hostname)
3190 s.connect((HOST, server.port))
3191 cert = s.getpeercert()
3192 self.assertEqual(s.server_hostname, expected_hostname)
3193 self.assertTrue(cert, "Can't get peer certificate.")
3194
Christian Heimes66e57422018-01-29 14:25:13 +01003195 # incorrect hostname should raise an exception
3196 server = ThreadedEchoServer(context=server_context, chatty=True)
3197 with server:
3198 with context.wrap_socket(socket.socket(),
3199 server_hostname="python.example.org") as s:
3200 with self.assertRaises(ssl.CertificateError):
3201 s.connect((HOST, server.port))
3202
Christian Heimes529525f2018-05-23 22:24:45 +02003203 def test_wrong_cert_tls12(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003204 """Connecting when the server rejects the client's certificate
3205
3206 Launch a server with CERT_REQUIRED, and check that trying to
3207 connect to it with a wrong client certificate fails.
3208 """
Christian Heimes05d9fe32018-02-27 08:55:39 +01003209 client_context, server_context, hostname = testing_context()
Christian Heimes88bfd0b2018-08-14 12:54:19 +02003210 # load client cert that is not signed by trusted CA
3211 client_context.load_cert_chain(CERTFILE)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003212 # require TLS client authentication
3213 server_context.verify_mode = ssl.CERT_REQUIRED
Christian Heimes529525f2018-05-23 22:24:45 +02003214 # TLS 1.3 has different handshake
3215 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimes05d9fe32018-02-27 08:55:39 +01003216
3217 server = ThreadedEchoServer(
3218 context=server_context, chatty=True, connectionchatty=True,
3219 )
3220
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003221 with server, \
Christian Heimes05d9fe32018-02-27 08:55:39 +01003222 client_context.wrap_socket(socket.socket(),
3223 server_hostname=hostname) as s:
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003224 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003225 # Expect either an SSL error about the server rejecting
3226 # the connection, or a low-level connection reset (which
3227 # sometimes happens on Windows)
3228 s.connect((HOST, server.port))
3229 except ssl.SSLError as e:
3230 if support.verbose:
3231 sys.stdout.write("\nSSLError is %r\n" % e)
3232 except OSError as e:
3233 if e.errno != errno.ECONNRESET:
3234 raise
3235 if support.verbose:
3236 sys.stdout.write("\nsocket.error is %r\n" % e)
3237 else:
3238 self.fail("Use of invalid cert should have failed!")
3239
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003240 @requires_tls_version('TLSv1_3')
Christian Heimes529525f2018-05-23 22:24:45 +02003241 def test_wrong_cert_tls13(self):
3242 client_context, server_context, hostname = testing_context()
Christian Heimes88bfd0b2018-08-14 12:54:19 +02003243 # load client cert that is not signed by trusted CA
3244 client_context.load_cert_chain(CERTFILE)
Christian Heimes529525f2018-05-23 22:24:45 +02003245 server_context.verify_mode = ssl.CERT_REQUIRED
3246 server_context.minimum_version = ssl.TLSVersion.TLSv1_3
3247 client_context.minimum_version = ssl.TLSVersion.TLSv1_3
3248
3249 server = ThreadedEchoServer(
3250 context=server_context, chatty=True, connectionchatty=True,
3251 )
3252 with server, \
3253 client_context.wrap_socket(socket.socket(),
Miss Islington (bot)d2ab15f2021-06-03 13:15:15 -07003254 server_hostname=hostname,
3255 suppress_ragged_eofs=False) as s:
Christian Heimes529525f2018-05-23 22:24:45 +02003256 # TLS 1.3 perform client cert exchange after handshake
3257 s.connect((HOST, server.port))
3258 try:
3259 s.write(b'data')
Christian Heimese0472392021-04-23 20:03:25 +02003260 s.read(1000)
3261 s.write(b'should have failed already')
3262 s.read(1000)
Christian Heimes529525f2018-05-23 22:24:45 +02003263 except ssl.SSLError as e:
3264 if support.verbose:
3265 sys.stdout.write("\nSSLError is %r\n" % e)
3266 except OSError as e:
3267 if e.errno != errno.ECONNRESET:
3268 raise
3269 if support.verbose:
3270 sys.stdout.write("\nsocket.error is %r\n" % e)
3271 else:
Miss Islington (bot)d2ab15f2021-06-03 13:15:15 -07003272 self.fail("Use of invalid cert should have failed!")
Christian Heimes529525f2018-05-23 22:24:45 +02003273
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003274 def test_rude_shutdown(self):
3275 """A brutal shutdown of an SSL server should raise an OSError
3276 in the client when attempting handshake.
3277 """
3278 listener_ready = threading.Event()
3279 listener_gone = threading.Event()
3280
3281 s = socket.socket()
Serhiy Storchaka16994912020-04-25 10:06:29 +03003282 port = socket_helper.bind_port(s, HOST)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003283
3284 # `listener` runs in a thread. It sits in an accept() until
3285 # the main thread connects. Then it rudely closes the socket,
3286 # and sets Event `listener_gone` to let the main thread know
3287 # the socket is gone.
3288 def listener():
3289 s.listen()
3290 listener_ready.set()
3291 newsock, addr = s.accept()
3292 newsock.close()
3293 s.close()
3294 listener_gone.set()
3295
3296 def connector():
3297 listener_ready.wait()
3298 with socket.socket() as c:
3299 c.connect((HOST, port))
3300 listener_gone.wait()
Antoine Pitrou40f08742010-04-24 22:04:40 +00003301 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003302 ssl_sock = test_wrap_socket(c)
3303 except OSError:
3304 pass
3305 else:
3306 self.fail('connecting to closed SSL socket should have failed')
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003307
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003308 t = threading.Thread(target=listener)
3309 t.start()
3310 try:
3311 connector()
3312 finally:
Antoine Pitrou5c89b4e2012-11-11 01:25:36 +01003313 t.join()
Antoine Pitrou5c89b4e2012-11-11 01:25:36 +01003314
Christian Heimesb3ad0e52017-09-08 12:00:19 -07003315 def test_ssl_cert_verify_error(self):
3316 if support.verbose:
3317 sys.stdout.write("\n")
3318
3319 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3320 server_context.load_cert_chain(SIGNED_CERTFILE)
3321
3322 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3323
3324 server = ThreadedEchoServer(context=server_context, chatty=True)
3325 with server:
3326 with context.wrap_socket(socket.socket(),
Christian Heimesa170fa12017-09-15 20:27:30 +02003327 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Christian Heimesb3ad0e52017-09-08 12:00:19 -07003328 try:
3329 s.connect((HOST, server.port))
3330 except ssl.SSLError as e:
3331 msg = 'unable to get local issuer certificate'
3332 self.assertIsInstance(e, ssl.SSLCertVerificationError)
3333 self.assertEqual(e.verify_code, 20)
3334 self.assertEqual(e.verify_message, msg)
3335 self.assertIn(msg, repr(e))
3336 self.assertIn('certificate verify failed', repr(e))
3337
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003338 @requires_tls_version('SSLv2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003339 def test_protocol_sslv2(self):
3340 """Connecting to an SSLv2 server with various client options"""
3341 if support.verbose:
3342 sys.stdout.write("\n")
3343 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
3344 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
3345 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
Christian Heimesa170fa12017-09-15 20:27:30 +02003346 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003347 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003348 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
3349 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
3350 # SSLv23 client with specific SSL options
Christian Heimesa170fa12017-09-15 20:27:30 +02003351 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003352 client_options=ssl.OP_NO_SSLv3)
Christian Heimesa170fa12017-09-15 20:27:30 +02003353 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003354 client_options=ssl.OP_NO_TLSv1)
Antoine Pitrou242db722013-05-01 20:52:07 +02003355
Christian Heimesa170fa12017-09-15 20:27:30 +02003356 def test_PROTOCOL_TLS(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003357 """Connecting to an SSLv23 server with various client options"""
3358 if support.verbose:
3359 sys.stdout.write("\n")
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003360 if has_tls_version('SSLv2'):
Antoine Pitrou8f85f902012-01-03 22:46:48 +01003361 try:
Christian Heimesa170fa12017-09-15 20:27:30 +02003362 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv2, True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003363 except OSError as x:
3364 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
3365 if support.verbose:
3366 sys.stdout.write(
3367 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
3368 % str(x))
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003369 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003370 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False)
3371 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003372 if has_tls_version('TLSv1'):
3373 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1')
Antoine Pitrou8f85f902012-01-03 22:46:48 +01003374
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003375 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003376 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False, ssl.CERT_OPTIONAL)
3377 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True, ssl.CERT_OPTIONAL)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003378 if has_tls_version('TLSv1'):
3379 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003380
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003381 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003382 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False, ssl.CERT_REQUIRED)
3383 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True, ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003384 if has_tls_version('TLSv1'):
3385 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003386
3387 # Server with specific SSL options
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003388 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003389 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003390 server_options=ssl.OP_NO_SSLv3)
3391 # Will choose TLSv1
Christian Heimesa170fa12017-09-15 20:27:30 +02003392 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003393 server_options=ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003394 if has_tls_version('TLSv1'):
3395 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, False,
3396 server_options=ssl.OP_NO_TLSv1)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003397
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003398 @requires_tls_version('SSLv3')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003399 def test_protocol_sslv3(self):
3400 """Connecting to an SSLv3 server with various client options"""
3401 if support.verbose:
3402 sys.stdout.write("\n")
3403 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3')
3404 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_OPTIONAL)
3405 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003406 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003407 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003408 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003409 client_options=ssl.OP_NO_SSLv3)
3410 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003411
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003412 @requires_tls_version('TLSv1')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003413 def test_protocol_tlsv1(self):
3414 """Connecting to a TLSv1 server with various client options"""
3415 if support.verbose:
3416 sys.stdout.write("\n")
3417 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1')
3418 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL)
3419 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003420 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003421 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003422 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003423 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003424 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003425 client_options=ssl.OP_NO_TLSv1)
3426
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003427 @requires_tls_version('TLSv1_1')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003428 def test_protocol_tlsv1_1(self):
3429 """Connecting to a TLSv1.1 server with various client options.
3430 Testing against older TLS versions."""
3431 if support.verbose:
3432 sys.stdout.write("\n")
3433 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1')
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003434 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003435 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003436 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003437 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003438 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003439 client_options=ssl.OP_NO_TLSv1_1)
3440
Christian Heimesa170fa12017-09-15 20:27:30 +02003441 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1')
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003442 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False)
3443 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003444
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003445 @requires_tls_version('TLSv1_2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003446 def test_protocol_tlsv1_2(self):
3447 """Connecting to a TLSv1.2 server with various client options.
3448 Testing against older TLS versions."""
3449 if support.verbose:
3450 sys.stdout.write("\n")
3451 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2',
3452 server_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,
3453 client_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003454 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003455 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003456 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003457 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003458 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003459 client_options=ssl.OP_NO_TLSv1_2)
3460
Christian Heimesa170fa12017-09-15 20:27:30 +02003461 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003462 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1, False)
3463 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_2, False)
3464 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False)
3465 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False)
3466
3467 def test_starttls(self):
3468 """Switching from clear text to encrypted and back again."""
3469 msgs = (b"msg 1", b"MSG 2", b"STARTTLS", b"MSG 3", b"msg 4", b"ENDTLS", b"msg 5", b"msg 6")
3470
3471 server = ThreadedEchoServer(CERTFILE,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003472 starttls_server=True,
3473 chatty=True,
3474 connectionchatty=True)
3475 wrapped = False
3476 with server:
3477 s = socket.socket()
Serhiy Storchaka5eca7f32019-09-01 12:12:52 +03003478 s.setblocking(True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003479 s.connect((HOST, server.port))
Antoine Pitroud6494802011-07-21 01:11:30 +02003480 if support.verbose:
3481 sys.stdout.write("\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003482 for indata in msgs:
Antoine Pitroud6494802011-07-21 01:11:30 +02003483 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003484 sys.stdout.write(
3485 " client: sending %r...\n" % indata)
3486 if wrapped:
3487 conn.write(indata)
3488 outdata = conn.read()
3489 else:
3490 s.send(indata)
3491 outdata = s.recv(1024)
3492 msg = outdata.strip().lower()
3493 if indata == b"STARTTLS" and msg.startswith(b"ok"):
3494 # STARTTLS ok, switch to secure mode
3495 if support.verbose:
3496 sys.stdout.write(
3497 " client: read %r from server, starting TLS...\n"
3498 % msg)
Christian Heimesa170fa12017-09-15 20:27:30 +02003499 conn = test_wrap_socket(s)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003500 wrapped = True
3501 elif indata == b"ENDTLS" and msg.startswith(b"ok"):
3502 # ENDTLS ok, switch back to clear text
3503 if support.verbose:
3504 sys.stdout.write(
3505 " client: read %r from server, ending TLS...\n"
3506 % msg)
3507 s = conn.unwrap()
3508 wrapped = False
3509 else:
3510 if support.verbose:
3511 sys.stdout.write(
3512 " client: read %r from server\n" % msg)
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003513 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003514 sys.stdout.write(" client: closing connection.\n")
3515 if wrapped:
3516 conn.write(b"over\n")
3517 else:
3518 s.send(b"over\n")
3519 if wrapped:
3520 conn.close()
3521 else:
3522 s.close()
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003523
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003524 def test_socketserver(self):
3525 """Using socketserver to create and manage SSL connections."""
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003526 server = make_https_server(self, certfile=SIGNED_CERTFILE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003527 # try to connect
3528 if support.verbose:
3529 sys.stdout.write('\n')
3530 with open(CERTFILE, 'rb') as f:
3531 d1 = f.read()
3532 d2 = ''
3533 # now fetch the same data from the HTTPS server
3534 url = 'https://localhost:%d/%s' % (
3535 server.port, os.path.split(CERTFILE)[1])
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003536 context = ssl.create_default_context(cafile=SIGNING_CA)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003537 f = urllib.request.urlopen(url, context=context)
3538 try:
3539 dlen = f.info().get("content-length")
3540 if dlen and (int(dlen) > 0):
3541 d2 = f.read(int(dlen))
3542 if support.verbose:
3543 sys.stdout.write(
3544 " client: read %d bytes from remote server '%s'\n"
3545 % (len(d2), server))
3546 finally:
3547 f.close()
3548 self.assertEqual(d1, d2)
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003549
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003550 def test_asyncore_server(self):
3551 """Check the example asyncore integration."""
3552 if support.verbose:
3553 sys.stdout.write("\n")
Antoine Pitrou0e576f12011-12-22 10:03:38 +01003554
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003555 indata = b"FOO\n"
3556 server = AsyncoreEchoServer(CERTFILE)
3557 with server:
3558 s = test_wrap_socket(socket.socket())
3559 s.connect(('127.0.0.1', server.port))
3560 if support.verbose:
3561 sys.stdout.write(
3562 " client: sending %r...\n" % indata)
3563 s.write(indata)
3564 outdata = s.read()
3565 if support.verbose:
3566 sys.stdout.write(" client: read %r\n" % outdata)
3567 if outdata != indata.lower():
3568 self.fail(
3569 "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
3570 % (outdata[:20], len(outdata),
3571 indata[:20].lower(), len(indata)))
3572 s.write(b"over\n")
3573 if support.verbose:
3574 sys.stdout.write(" client: closing connection.\n")
3575 s.close()
3576 if support.verbose:
3577 sys.stdout.write(" client: connection closed.\n")
Benjamin Petersoncca27322015-01-23 16:35:37 -05003578
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003579 def test_recv_send(self):
3580 """Test recv(), send() and friends."""
3581 if support.verbose:
3582 sys.stdout.write("\n")
3583
3584 server = ThreadedEchoServer(CERTFILE,
3585 certreqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003586 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003587 cacerts=CERTFILE,
3588 chatty=True,
3589 connectionchatty=False)
3590 with server:
3591 s = test_wrap_socket(socket.socket(),
3592 server_side=False,
3593 certfile=CERTFILE,
3594 ca_certs=CERTFILE,
Christian Heimes2875c602021-04-19 07:27:10 +02003595 cert_reqs=ssl.CERT_NONE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003596 s.connect((HOST, server.port))
3597 # helper methods for standardising recv* method signatures
3598 def _recv_into():
3599 b = bytearray(b"\0"*100)
3600 count = s.recv_into(b)
3601 return b[:count]
3602
3603 def _recvfrom_into():
3604 b = bytearray(b"\0"*100)
3605 count, addr = s.recvfrom_into(b)
3606 return b[:count]
3607
3608 # (name, method, expect success?, *args, return value func)
3609 send_methods = [
3610 ('send', s.send, True, [], len),
3611 ('sendto', s.sendto, False, ["some.address"], len),
3612 ('sendall', s.sendall, True, [], lambda x: None),
3613 ]
3614 # (name, method, whether to expect success, *args)
3615 recv_methods = [
3616 ('recv', s.recv, True, []),
3617 ('recvfrom', s.recvfrom, False, ["some.address"]),
3618 ('recv_into', _recv_into, True, []),
3619 ('recvfrom_into', _recvfrom_into, False, []),
3620 ]
3621 data_prefix = "PREFIX_"
3622
3623 for (meth_name, send_meth, expect_success, args,
3624 ret_val_meth) in send_methods:
3625 indata = (data_prefix + meth_name).encode('ascii')
3626 try:
3627 ret = send_meth(indata, *args)
3628 msg = "sending with {}".format(meth_name)
3629 self.assertEqual(ret, ret_val_meth(indata), msg=msg)
3630 outdata = s.read()
3631 if outdata != indata.lower():
3632 self.fail(
3633 "While sending with <<{name:s}>> bad data "
3634 "<<{outdata:r}>> ({nout:d}) received; "
3635 "expected <<{indata:r}>> ({nin:d})\n".format(
3636 name=meth_name, outdata=outdata[:20],
3637 nout=len(outdata),
3638 indata=indata[:20], nin=len(indata)
3639 )
3640 )
3641 except ValueError as e:
3642 if expect_success:
3643 self.fail(
3644 "Failed to send with method <<{name:s}>>; "
3645 "expected to succeed.\n".format(name=meth_name)
3646 )
3647 if not str(e).startswith(meth_name):
3648 self.fail(
3649 "Method <<{name:s}>> failed with unexpected "
3650 "exception message: {exp:s}\n".format(
3651 name=meth_name, exp=e
3652 )
3653 )
3654
3655 for meth_name, recv_meth, expect_success, args in recv_methods:
3656 indata = (data_prefix + meth_name).encode('ascii')
3657 try:
3658 s.send(indata)
3659 outdata = recv_meth(*args)
3660 if outdata != indata.lower():
3661 self.fail(
3662 "While receiving with <<{name:s}>> bad data "
3663 "<<{outdata:r}>> ({nout:d}) received; "
3664 "expected <<{indata:r}>> ({nin:d})\n".format(
3665 name=meth_name, outdata=outdata[:20],
3666 nout=len(outdata),
3667 indata=indata[:20], nin=len(indata)
3668 )
3669 )
3670 except ValueError as e:
3671 if expect_success:
3672 self.fail(
3673 "Failed to receive with method <<{name:s}>>; "
3674 "expected to succeed.\n".format(name=meth_name)
3675 )
3676 if not str(e).startswith(meth_name):
3677 self.fail(
3678 "Method <<{name:s}>> failed with unexpected "
3679 "exception message: {exp:s}\n".format(
3680 name=meth_name, exp=e
3681 )
3682 )
3683 # consume data
3684 s.read()
3685
3686 # read(-1, buffer) is supported, even though read(-1) is not
3687 data = b"data"
3688 s.send(data)
3689 buffer = bytearray(len(data))
3690 self.assertEqual(s.read(-1, buffer), len(data))
3691 self.assertEqual(buffer, data)
3692
Christian Heimes888bbdc2017-09-07 14:18:21 -07003693 # sendall accepts bytes-like objects
3694 if ctypes is not None:
3695 ubyte = ctypes.c_ubyte * len(data)
3696 byteslike = ubyte.from_buffer_copy(data)
3697 s.sendall(byteslike)
3698 self.assertEqual(s.read(), data)
3699
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003700 # Make sure sendmsg et al are disallowed to avoid
3701 # inadvertent disclosure of data and/or corruption
3702 # of the encrypted data stream
Serhiy Storchaka42b1d612018-12-06 22:36:55 +02003703 self.assertRaises(NotImplementedError, s.dup)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003704 self.assertRaises(NotImplementedError, s.sendmsg, [b"data"])
3705 self.assertRaises(NotImplementedError, s.recvmsg, 100)
3706 self.assertRaises(NotImplementedError,
Serhiy Storchaka42b1d612018-12-06 22:36:55 +02003707 s.recvmsg_into, [bytearray(100)])
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003708 s.write(b"over\n")
3709
3710 self.assertRaises(ValueError, s.recv, -1)
3711 self.assertRaises(ValueError, s.read, -1)
3712
3713 s.close()
3714
3715 def test_recv_zero(self):
3716 server = ThreadedEchoServer(CERTFILE)
3717 server.__enter__()
3718 self.addCleanup(server.__exit__, None, None)
3719 s = socket.create_connection((HOST, server.port))
3720 self.addCleanup(s.close)
3721 s = test_wrap_socket(s, suppress_ragged_eofs=False)
3722 self.addCleanup(s.close)
3723
3724 # recv/read(0) should return no data
3725 s.send(b"data")
3726 self.assertEqual(s.recv(0), b"")
3727 self.assertEqual(s.read(0), b"")
3728 self.assertEqual(s.read(), b"data")
3729
3730 # Should not block if the other end sends no data
3731 s.setblocking(False)
3732 self.assertEqual(s.recv(0), b"")
3733 self.assertEqual(s.recv_into(bytearray()), 0)
3734
3735 def test_nonblocking_send(self):
3736 server = ThreadedEchoServer(CERTFILE,
3737 certreqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003738 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003739 cacerts=CERTFILE,
3740 chatty=True,
3741 connectionchatty=False)
3742 with server:
3743 s = test_wrap_socket(socket.socket(),
3744 server_side=False,
3745 certfile=CERTFILE,
3746 ca_certs=CERTFILE,
Christian Heimes2875c602021-04-19 07:27:10 +02003747 cert_reqs=ssl.CERT_NONE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003748 s.connect((HOST, server.port))
3749 s.setblocking(False)
3750
3751 # If we keep sending data, at some point the buffers
3752 # will be full and the call will block
3753 buf = bytearray(8192)
3754 def fill_buffer():
3755 while True:
3756 s.send(buf)
3757 self.assertRaises((ssl.SSLWantWriteError,
3758 ssl.SSLWantReadError), fill_buffer)
3759
3760 # Now read all the output and discard it
3761 s.setblocking(True)
3762 s.close()
3763
3764 def test_handshake_timeout(self):
3765 # Issue #5103: SSL handshake must respect the socket timeout
3766 server = socket.socket(socket.AF_INET)
3767 host = "127.0.0.1"
Serhiy Storchaka16994912020-04-25 10:06:29 +03003768 port = socket_helper.bind_port(server)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003769 started = threading.Event()
3770 finish = False
3771
3772 def serve():
3773 server.listen()
3774 started.set()
3775 conns = []
3776 while not finish:
3777 r, w, e = select.select([server], [], [], 0.1)
3778 if server in r:
3779 # Let the socket hang around rather than having
3780 # it closed by garbage collection.
3781 conns.append(server.accept()[0])
3782 for sock in conns:
3783 sock.close()
3784
3785 t = threading.Thread(target=serve)
3786 t.start()
3787 started.wait()
3788
3789 try:
3790 try:
3791 c = socket.socket(socket.AF_INET)
3792 c.settimeout(0.2)
3793 c.connect((host, port))
3794 # Will attempt handshake and time out
Christian Heimes03c8ddd2020-11-20 09:26:07 +01003795 self.assertRaisesRegex(TimeoutError, "timed out",
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003796 test_wrap_socket, c)
3797 finally:
3798 c.close()
3799 try:
3800 c = socket.socket(socket.AF_INET)
3801 c = test_wrap_socket(c)
3802 c.settimeout(0.2)
3803 # Will attempt handshake and time out
Christian Heimes03c8ddd2020-11-20 09:26:07 +01003804 self.assertRaisesRegex(TimeoutError, "timed out",
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003805 c.connect, (host, port))
3806 finally:
3807 c.close()
3808 finally:
3809 finish = True
3810 t.join()
3811 server.close()
3812
3813 def test_server_accept(self):
3814 # Issue #16357: accept() on a SSLSocket created through
3815 # SSLContext.wrap_socket().
Christian Heimes2875c602021-04-19 07:27:10 +02003816 client_ctx, server_ctx, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003817 server = socket.socket(socket.AF_INET)
3818 host = "127.0.0.1"
Serhiy Storchaka16994912020-04-25 10:06:29 +03003819 port = socket_helper.bind_port(server)
Christian Heimes2875c602021-04-19 07:27:10 +02003820 server = server_ctx.wrap_socket(server, server_side=True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003821 self.assertTrue(server.server_side)
3822
3823 evt = threading.Event()
3824 remote = None
3825 peer = None
3826 def serve():
3827 nonlocal remote, peer
3828 server.listen()
3829 # Block on the accept and wait on the connection to close.
3830 evt.set()
3831 remote, peer = server.accept()
Christian Heimes529525f2018-05-23 22:24:45 +02003832 remote.send(remote.recv(4))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003833
3834 t = threading.Thread(target=serve)
3835 t.start()
3836 # Client wait until server setup and perform a connect.
3837 evt.wait()
Christian Heimes2875c602021-04-19 07:27:10 +02003838 client = client_ctx.wrap_socket(
3839 socket.socket(), server_hostname=hostname
3840 )
3841 client.connect((hostname, port))
Christian Heimes529525f2018-05-23 22:24:45 +02003842 client.send(b'data')
3843 client.recv()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003844 client_addr = client.getsockname()
3845 client.close()
3846 t.join()
3847 remote.close()
3848 server.close()
3849 # Sanity checks.
3850 self.assertIsInstance(remote, ssl.SSLSocket)
3851 self.assertEqual(peer, client_addr)
3852
3853 def test_getpeercert_enotconn(self):
Christian Heimes2875c602021-04-19 07:27:10 +02003854 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3855 context.check_hostname = False
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003856 with context.wrap_socket(socket.socket()) as sock:
3857 with self.assertRaises(OSError) as cm:
3858 sock.getpeercert()
3859 self.assertEqual(cm.exception.errno, errno.ENOTCONN)
3860
3861 def test_do_handshake_enotconn(self):
Christian Heimes2875c602021-04-19 07:27:10 +02003862 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3863 context.check_hostname = False
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003864 with context.wrap_socket(socket.socket()) as sock:
3865 with self.assertRaises(OSError) as cm:
3866 sock.do_handshake()
3867 self.assertEqual(cm.exception.errno, errno.ENOTCONN)
3868
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003869 def test_no_shared_ciphers(self):
3870 client_context, server_context, hostname = testing_context()
3871 # OpenSSL enables all TLS 1.3 ciphers, enforce TLS 1.2 for test
Miss Islington (bot)4becc562021-06-13 05:07:00 -07003872 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Victor Stinner5e922652018-09-07 17:30:33 +02003873 # Force different suites on client and server
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003874 client_context.set_ciphers("AES128")
3875 server_context.set_ciphers("AES256")
3876 with ThreadedEchoServer(context=server_context) as server:
3877 with client_context.wrap_socket(socket.socket(),
3878 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003879 with self.assertRaises(OSError):
3880 s.connect((HOST, server.port))
3881 self.assertIn("no shared cipher", server.conn_errors[0])
3882
3883 def test_version_basic(self):
3884 """
3885 Basic tests for SSLSocket.version().
3886 More tests are done in the test_protocol_*() methods.
3887 """
Christian Heimesa170fa12017-09-15 20:27:30 +02003888 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3889 context.check_hostname = False
3890 context.verify_mode = ssl.CERT_NONE
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003891 with ThreadedEchoServer(CERTFILE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003892 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003893 chatty=False) as server:
3894 with context.wrap_socket(socket.socket()) as s:
3895 self.assertIs(s.version(), None)
Christian Heimes141c5e82018-02-24 21:10:57 +01003896 self.assertIs(s._sslobj, None)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003897 s.connect((HOST, server.port))
Christian Heimes39258d32021-04-17 11:36:35 +02003898 self.assertEqual(s.version(), 'TLSv1.3')
Christian Heimes141c5e82018-02-24 21:10:57 +01003899 self.assertIs(s._sslobj, None)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003900 self.assertIs(s.version(), None)
3901
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003902 @requires_tls_version('TLSv1_3')
Christian Heimescb5b68a2017-09-07 18:07:00 -07003903 def test_tls1_3(self):
Christian Heimes2875c602021-04-19 07:27:10 +02003904 client_context, server_context, hostname = testing_context()
3905 client_context.minimum_version = ssl.TLSVersion.TLSv1_3
3906 with ThreadedEchoServer(context=server_context) as server:
3907 with client_context.wrap_socket(socket.socket(),
3908 server_hostname=hostname) as s:
Christian Heimescb5b68a2017-09-07 18:07:00 -07003909 s.connect((HOST, server.port))
Christian Heimes05d9fe32018-02-27 08:55:39 +01003910 self.assertIn(s.cipher()[0], {
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003911 'TLS_AES_256_GCM_SHA384',
3912 'TLS_CHACHA20_POLY1305_SHA256',
3913 'TLS_AES_128_GCM_SHA256',
Christian Heimes05d9fe32018-02-27 08:55:39 +01003914 })
3915 self.assertEqual(s.version(), 'TLSv1.3')
Christian Heimescb5b68a2017-09-07 18:07:00 -07003916
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003917 @requires_tls_version('TLSv1_2')
Christian Heimes2875c602021-04-19 07:27:10 +02003918 @requires_tls_version('TLSv1')
3919 @ignore_deprecation
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003920 def test_min_max_version_tlsv1_2(self):
Christian Heimes698dde12018-02-27 11:54:43 +01003921 client_context, server_context, hostname = testing_context()
3922 # client TLSv1.0 to 1.2
3923 client_context.minimum_version = ssl.TLSVersion.TLSv1
3924 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
3925 # server only TLSv1.2
3926 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
3927 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
3928
3929 with ThreadedEchoServer(context=server_context) as server:
3930 with client_context.wrap_socket(socket.socket(),
3931 server_hostname=hostname) as s:
3932 s.connect((HOST, server.port))
3933 self.assertEqual(s.version(), 'TLSv1.2')
3934
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003935 @requires_tls_version('TLSv1_1')
Christian Heimes2875c602021-04-19 07:27:10 +02003936 @ignore_deprecation
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003937 def test_min_max_version_tlsv1_1(self):
3938 client_context, server_context, hostname = testing_context()
Christian Heimes698dde12018-02-27 11:54:43 +01003939 # client 1.0 to 1.2, server 1.0 to 1.1
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003940 client_context.minimum_version = ssl.TLSVersion.TLSv1
3941 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimes698dde12018-02-27 11:54:43 +01003942 server_context.minimum_version = ssl.TLSVersion.TLSv1
3943 server_context.maximum_version = ssl.TLSVersion.TLSv1_1
Christian Heimesf6c6b582021-03-18 23:06:50 +01003944 seclevel_workaround(client_context, server_context)
Christian Heimes698dde12018-02-27 11:54:43 +01003945
3946 with ThreadedEchoServer(context=server_context) as server:
3947 with client_context.wrap_socket(socket.socket(),
3948 server_hostname=hostname) as s:
3949 s.connect((HOST, server.port))
3950 self.assertEqual(s.version(), 'TLSv1.1')
3951
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003952 @requires_tls_version('TLSv1_2')
Christian Heimesce04e712020-11-18 13:10:53 +01003953 @requires_tls_version('TLSv1')
Christian Heimes2875c602021-04-19 07:27:10 +02003954 @ignore_deprecation
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003955 def test_min_max_version_mismatch(self):
3956 client_context, server_context, hostname = testing_context()
Christian Heimes698dde12018-02-27 11:54:43 +01003957 # client 1.0, server 1.2 (mismatch)
Christian Heimes698dde12018-02-27 11:54:43 +01003958 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesc9bc49c2019-09-11 19:24:47 +02003959 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
Christian Heimese35d1ba2019-06-03 20:40:15 +02003960 client_context.maximum_version = ssl.TLSVersion.TLSv1
Christian Heimesde606ea2019-09-11 19:48:58 +02003961 client_context.minimum_version = ssl.TLSVersion.TLSv1
Christian Heimesf6c6b582021-03-18 23:06:50 +01003962 seclevel_workaround(client_context, server_context)
3963
Christian Heimes698dde12018-02-27 11:54:43 +01003964 with ThreadedEchoServer(context=server_context) as server:
3965 with client_context.wrap_socket(socket.socket(),
3966 server_hostname=hostname) as s:
3967 with self.assertRaises(ssl.SSLError) as e:
3968 s.connect((HOST, server.port))
3969 self.assertIn("alert", str(e.exception))
3970
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003971 @requires_tls_version('SSLv3')
Christian Heimes698dde12018-02-27 11:54:43 +01003972 def test_min_max_version_sslv3(self):
3973 client_context, server_context, hostname = testing_context()
3974 server_context.minimum_version = ssl.TLSVersion.SSLv3
3975 client_context.minimum_version = ssl.TLSVersion.SSLv3
3976 client_context.maximum_version = ssl.TLSVersion.SSLv3
Christian Heimesf6c6b582021-03-18 23:06:50 +01003977 seclevel_workaround(client_context, server_context)
3978
Christian Heimes698dde12018-02-27 11:54:43 +01003979 with ThreadedEchoServer(context=server_context) as server:
3980 with client_context.wrap_socket(socket.socket(),
3981 server_hostname=hostname) as s:
3982 s.connect((HOST, server.port))
3983 self.assertEqual(s.version(), 'SSLv3')
3984
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003985 def test_default_ecdh_curve(self):
3986 # Issue #21015: elliptic curve-based Diffie Hellman key exchange
3987 # should be enabled by default on SSL contexts.
Christian Heimes2875c602021-04-19 07:27:10 +02003988 client_context, server_context, hostname = testing_context()
Christian Heimescb5b68a2017-09-07 18:07:00 -07003989 # TLSv1.3 defaults to PFS key agreement and no longer has KEA in
3990 # cipher name.
Christian Heimes2875c602021-04-19 07:27:10 +02003991 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003992 # Prior to OpenSSL 1.0.0, ECDH ciphers have to be enabled
3993 # explicitly using the 'ECCdraft' cipher alias. Otherwise,
3994 # our default cipher list should prefer ECDH-based ciphers
3995 # automatically.
Christian Heimes2875c602021-04-19 07:27:10 +02003996 with ThreadedEchoServer(context=server_context) as server:
3997 with client_context.wrap_socket(socket.socket(),
3998 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003999 s.connect((HOST, server.port))
4000 self.assertIn("ECDH", s.cipher()[0])
4001
4002 @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES,
4003 "'tls-unique' channel binding not available")
4004 def test_tls_unique_channel_binding(self):
4005 """Test tls-unique channel binding."""
4006 if support.verbose:
4007 sys.stdout.write("\n")
4008
Christian Heimes05d9fe32018-02-27 08:55:39 +01004009 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004010
4011 server = ThreadedEchoServer(context=server_context,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004012 chatty=True,
4013 connectionchatty=False)
Christian Heimes05d9fe32018-02-27 08:55:39 +01004014
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004015 with server:
Christian Heimes05d9fe32018-02-27 08:55:39 +01004016 with client_context.wrap_socket(
4017 socket.socket(),
4018 server_hostname=hostname) as s:
4019 s.connect((HOST, server.port))
4020 # get the data
4021 cb_data = s.get_channel_binding("tls-unique")
4022 if support.verbose:
4023 sys.stdout.write(
4024 " got channel binding data: {0!r}\n".format(cb_data))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004025
Christian Heimes05d9fe32018-02-27 08:55:39 +01004026 # check if it is sane
4027 self.assertIsNotNone(cb_data)
Christian Heimes529525f2018-05-23 22:24:45 +02004028 if s.version() == 'TLSv1.3':
4029 self.assertEqual(len(cb_data), 48)
4030 else:
4031 self.assertEqual(len(cb_data), 12) # True for TLSv1
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004032
Christian Heimes05d9fe32018-02-27 08:55:39 +01004033 # and compare with the peers version
4034 s.write(b"CB tls-unique\n")
4035 peer_data_repr = s.read().strip()
4036 self.assertEqual(peer_data_repr,
4037 repr(cb_data).encode("us-ascii"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004038
4039 # now, again
Christian Heimes05d9fe32018-02-27 08:55:39 +01004040 with client_context.wrap_socket(
4041 socket.socket(),
4042 server_hostname=hostname) as s:
4043 s.connect((HOST, server.port))
4044 new_cb_data = s.get_channel_binding("tls-unique")
4045 if support.verbose:
4046 sys.stdout.write(
4047 "got another channel binding data: {0!r}\n".format(
4048 new_cb_data)
4049 )
4050 # is it really unique
4051 self.assertNotEqual(cb_data, new_cb_data)
4052 self.assertIsNotNone(cb_data)
Christian Heimes529525f2018-05-23 22:24:45 +02004053 if s.version() == 'TLSv1.3':
4054 self.assertEqual(len(cb_data), 48)
4055 else:
4056 self.assertEqual(len(cb_data), 12) # True for TLSv1
Christian Heimes05d9fe32018-02-27 08:55:39 +01004057 s.write(b"CB tls-unique\n")
4058 peer_data_repr = s.read().strip()
4059 self.assertEqual(peer_data_repr,
4060 repr(new_cb_data).encode("us-ascii"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004061
4062 def test_compression(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004063 client_context, server_context, hostname = testing_context()
4064 stats = server_params_test(client_context, server_context,
4065 chatty=True, connectionchatty=True,
4066 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004067 if support.verbose:
4068 sys.stdout.write(" got compression: {!r}\n".format(stats['compression']))
4069 self.assertIn(stats['compression'], { None, 'ZLIB', 'RLE' })
4070
4071 @unittest.skipUnless(hasattr(ssl, 'OP_NO_COMPRESSION'),
4072 "ssl.OP_NO_COMPRESSION needed for this test")
4073 def test_compression_disabled(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004074 client_context, server_context, hostname = testing_context()
4075 client_context.options |= ssl.OP_NO_COMPRESSION
4076 server_context.options |= ssl.OP_NO_COMPRESSION
4077 stats = server_params_test(client_context, server_context,
4078 chatty=True, connectionchatty=True,
4079 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004080 self.assertIs(stats['compression'], None)
4081
Paul Monsonf3550692019-06-19 13:09:54 -07004082 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004083 def test_dh_params(self):
4084 # Check we can get a connection with ephemeral Diffie-Hellman
Christian Heimesa170fa12017-09-15 20:27:30 +02004085 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004086 # test scenario needs TLS <= 1.2
Miss Islington (bot)4becc562021-06-13 05:07:00 -07004087 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesa170fa12017-09-15 20:27:30 +02004088 server_context.load_dh_params(DHFILE)
4089 server_context.set_ciphers("kEDH")
Miss Islington (bot)4becc562021-06-13 05:07:00 -07004090 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesa170fa12017-09-15 20:27:30 +02004091 stats = server_params_test(client_context, server_context,
4092 chatty=True, connectionchatty=True,
4093 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004094 cipher = stats["cipher"][0]
4095 parts = cipher.split("-")
4096 if "ADH" not in parts and "EDH" not in parts and "DHE" not in parts:
4097 self.fail("Non-DH cipher: " + cipher[0])
4098
Christian Heimesb7b92252018-02-25 09:49:31 +01004099 def test_ecdh_curve(self):
4100 # server secp384r1, client auto
4101 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004102
Christian Heimesb7b92252018-02-25 09:49:31 +01004103 server_context.set_ecdh_curve("secp384r1")
4104 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
Christian Heimesd37b74f2021-04-19 08:31:29 +02004105 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesb7b92252018-02-25 09:49:31 +01004106 stats = server_params_test(client_context, server_context,
4107 chatty=True, connectionchatty=True,
4108 sni_name=hostname)
4109
4110 # server auto, client secp384r1
4111 client_context, server_context, hostname = testing_context()
4112 client_context.set_ecdh_curve("secp384r1")
4113 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
Christian Heimesd37b74f2021-04-19 08:31:29 +02004114 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesb7b92252018-02-25 09:49:31 +01004115 stats = server_params_test(client_context, server_context,
4116 chatty=True, connectionchatty=True,
4117 sni_name=hostname)
4118
4119 # server / client curve mismatch
4120 client_context, server_context, hostname = testing_context()
4121 client_context.set_ecdh_curve("prime256v1")
4122 server_context.set_ecdh_curve("secp384r1")
4123 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
Christian Heimesd37b74f2021-04-19 08:31:29 +02004124 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
4125 with self.assertRaises(ssl.SSLError):
Christian Heimes39258d32021-04-17 11:36:35 +02004126 server_params_test(client_context, server_context,
4127 chatty=True, connectionchatty=True,
4128 sni_name=hostname)
Christian Heimesb7b92252018-02-25 09:49:31 +01004129
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004130 def test_selected_alpn_protocol(self):
4131 # selected_alpn_protocol() is None unless ALPN is used.
Christian Heimesa170fa12017-09-15 20:27:30 +02004132 client_context, server_context, hostname = testing_context()
4133 stats = server_params_test(client_context, server_context,
4134 chatty=True, connectionchatty=True,
4135 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004136 self.assertIs(stats['client_alpn_protocol'], None)
4137
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004138 def test_selected_alpn_protocol_if_server_uses_alpn(self):
4139 # selected_alpn_protocol() is None unless ALPN is used by the client.
Christian Heimesa170fa12017-09-15 20:27:30 +02004140 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004141 server_context.set_alpn_protocols(['foo', 'bar'])
4142 stats = server_params_test(client_context, server_context,
Christian Heimesa170fa12017-09-15 20:27:30 +02004143 chatty=True, connectionchatty=True,
4144 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004145 self.assertIs(stats['client_alpn_protocol'], None)
4146
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004147 def test_alpn_protocols(self):
4148 server_protocols = ['foo', 'bar', 'milkshake']
4149 protocol_tests = [
4150 (['foo', 'bar'], 'foo'),
4151 (['bar', 'foo'], 'foo'),
4152 (['milkshake'], 'milkshake'),
4153 (['http/3.0', 'http/4.0'], None)
4154 ]
4155 for client_protocols, expected in protocol_tests:
Christian Heimesa170fa12017-09-15 20:27:30 +02004156 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004157 server_context.set_alpn_protocols(server_protocols)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004158 client_context.set_alpn_protocols(client_protocols)
4159
4160 try:
4161 stats = server_params_test(client_context,
4162 server_context,
4163 chatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02004164 connectionchatty=True,
4165 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004166 except ssl.SSLError as e:
4167 stats = e
4168
Christian Heimes39258d32021-04-17 11:36:35 +02004169 msg = "failed trying %s (s) and %s (c).\n" \
4170 "was expecting %s, but got %%s from the %%s" \
4171 % (str(server_protocols), str(client_protocols),
4172 str(expected))
4173 client_result = stats['client_alpn_protocol']
4174 self.assertEqual(client_result, expected,
4175 msg % (client_result, "client"))
4176 server_result = stats['server_alpn_protocols'][-1] \
4177 if len(stats['server_alpn_protocols']) else 'nothing'
4178 self.assertEqual(server_result, expected,
4179 msg % (server_result, "server"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004180
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004181 def test_npn_protocols(self):
Christian Heimes39258d32021-04-17 11:36:35 +02004182 assert not ssl.HAS_NPN
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004183
4184 def sni_contexts(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004185 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004186 server_context.load_cert_chain(SIGNED_CERTFILE)
Christian Heimesa170fa12017-09-15 20:27:30 +02004187 other_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004188 other_context.load_cert_chain(SIGNED_CERTFILE2)
Christian Heimesa170fa12017-09-15 20:27:30 +02004189 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004190 client_context.load_verify_locations(SIGNING_CA)
4191 return server_context, other_context, client_context
4192
4193 def check_common_name(self, stats, name):
4194 cert = stats['peercert']
4195 self.assertIn((('commonName', name),), cert['subject'])
4196
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004197 def test_sni_callback(self):
4198 calls = []
4199 server_context, other_context, client_context = self.sni_contexts()
4200
Christian Heimesa170fa12017-09-15 20:27:30 +02004201 client_context.check_hostname = False
4202
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004203 def servername_cb(ssl_sock, server_name, initial_context):
4204 calls.append((server_name, initial_context))
4205 if server_name is not None:
4206 ssl_sock.context = other_context
4207 server_context.set_servername_callback(servername_cb)
4208
4209 stats = server_params_test(client_context, server_context,
4210 chatty=True,
4211 sni_name='supermessage')
4212 # The hostname was fetched properly, and the certificate was
4213 # changed for the connection.
4214 self.assertEqual(calls, [("supermessage", server_context)])
4215 # CERTFILE4 was selected
4216 self.check_common_name(stats, 'fakehostname')
4217
4218 calls = []
4219 # The callback is called with server_name=None
4220 stats = server_params_test(client_context, server_context,
4221 chatty=True,
4222 sni_name=None)
4223 self.assertEqual(calls, [(None, server_context)])
Christian Heimesa170fa12017-09-15 20:27:30 +02004224 self.check_common_name(stats, SIGNED_CERTFILE_HOSTNAME)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004225
4226 # Check disabling the callback
4227 calls = []
4228 server_context.set_servername_callback(None)
4229
4230 stats = server_params_test(client_context, server_context,
4231 chatty=True,
4232 sni_name='notfunny')
4233 # Certificate didn't change
Christian Heimesa170fa12017-09-15 20:27:30 +02004234 self.check_common_name(stats, SIGNED_CERTFILE_HOSTNAME)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004235 self.assertEqual(calls, [])
4236
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004237 def test_sni_callback_alert(self):
4238 # Returning a TLS alert is reflected to the connecting client
4239 server_context, other_context, client_context = self.sni_contexts()
4240
4241 def cb_returning_alert(ssl_sock, server_name, initial_context):
4242 return ssl.ALERT_DESCRIPTION_ACCESS_DENIED
4243 server_context.set_servername_callback(cb_returning_alert)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004244 with self.assertRaises(ssl.SSLError) as cm:
4245 stats = server_params_test(client_context, server_context,
4246 chatty=False,
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004247 sni_name='supermessage')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004248 self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_ACCESS_DENIED')
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004249
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004250 def test_sni_callback_raising(self):
4251 # Raising fails the connection with a TLS handshake failure alert.
4252 server_context, other_context, client_context = self.sni_contexts()
4253
4254 def cb_raising(ssl_sock, server_name, initial_context):
4255 1/0
4256 server_context.set_servername_callback(cb_raising)
4257
Victor Stinner00253502019-06-03 03:51:43 +02004258 with support.catch_unraisable_exception() as catch:
4259 with self.assertRaises(ssl.SSLError) as cm:
4260 stats = server_params_test(client_context, server_context,
4261 chatty=False,
4262 sni_name='supermessage')
4263
4264 self.assertEqual(cm.exception.reason,
4265 'SSLV3_ALERT_HANDSHAKE_FAILURE')
4266 self.assertEqual(catch.unraisable.exc_type, ZeroDivisionError)
Antoine Pitrou50b24d02013-04-11 20:48:42 +02004267
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004268 def test_sni_callback_wrong_return_type(self):
4269 # Returning the wrong return type terminates the TLS connection
4270 # with an internal error alert.
4271 server_context, other_context, client_context = self.sni_contexts()
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004272
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004273 def cb_wrong_return_type(ssl_sock, server_name, initial_context):
4274 return "foo"
4275 server_context.set_servername_callback(cb_wrong_return_type)
4276
Victor Stinner00253502019-06-03 03:51:43 +02004277 with support.catch_unraisable_exception() as catch:
4278 with self.assertRaises(ssl.SSLError) as cm:
4279 stats = server_params_test(client_context, server_context,
4280 chatty=False,
4281 sni_name='supermessage')
4282
4283
4284 self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_INTERNAL_ERROR')
4285 self.assertEqual(catch.unraisable.exc_type, TypeError)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004286
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004287 def test_shared_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004288 client_context, server_context, hostname = testing_context()
Christian Heimese8eb6cb2018-05-22 22:50:12 +02004289 client_context.set_ciphers("AES128:AES256")
4290 server_context.set_ciphers("AES256")
4291 expected_algs = [
4292 "AES256", "AES-256",
4293 # TLS 1.3 ciphers are always enabled
4294 "TLS_CHACHA20", "TLS_AES",
4295 ]
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004296
Christian Heimesa170fa12017-09-15 20:27:30 +02004297 stats = server_params_test(client_context, server_context,
4298 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004299 ciphers = stats['server_shared_ciphers'][0]
4300 self.assertGreater(len(ciphers), 0)
4301 for name, tls_version, bits in ciphers:
Christian Heimese8eb6cb2018-05-22 22:50:12 +02004302 if not any(alg in name for alg in expected_algs):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004303 self.fail(name)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004304
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004305 def test_read_write_after_close_raises_valuerror(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004306 client_context, server_context, hostname = testing_context()
4307 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004308
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004309 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02004310 s = client_context.wrap_socket(socket.socket(),
4311 server_hostname=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004312 s.connect((HOST, server.port))
4313 s.close()
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004314
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004315 self.assertRaises(ValueError, s.read, 1024)
4316 self.assertRaises(ValueError, s.write, b'hello')
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004317
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004318 def test_sendfile(self):
4319 TEST_DATA = b"x" * 512
Hai Shia7f5d932020-08-04 00:41:24 +08004320 with open(os_helper.TESTFN, 'wb') as f:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004321 f.write(TEST_DATA)
Hai Shia7f5d932020-08-04 00:41:24 +08004322 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimes2875c602021-04-19 07:27:10 +02004323 client_context, server_context, hostname = testing_context()
4324 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004325 with server:
Christian Heimes2875c602021-04-19 07:27:10 +02004326 with client_context.wrap_socket(socket.socket(),
4327 server_hostname=hostname) as s:
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004328 s.connect((HOST, server.port))
Hai Shia7f5d932020-08-04 00:41:24 +08004329 with open(os_helper.TESTFN, 'rb') as file:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004330 s.sendfile(file)
4331 self.assertEqual(s.recv(1024), TEST_DATA)
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004332
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004333 def test_session(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004334 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004335 # TODO: sessions aren't compatible with TLSv1.3 yet
Miss Islington (bot)4becc562021-06-13 05:07:00 -07004336 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004337
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004338 # first connection without session
Christian Heimesa170fa12017-09-15 20:27:30 +02004339 stats = server_params_test(client_context, server_context,
4340 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004341 session = stats['session']
4342 self.assertTrue(session.id)
4343 self.assertGreater(session.time, 0)
4344 self.assertGreater(session.timeout, 0)
4345 self.assertTrue(session.has_ticket)
Christian Heimes39258d32021-04-17 11:36:35 +02004346 self.assertGreater(session.ticket_lifetime_hint, 0)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004347 self.assertFalse(stats['session_reused'])
4348 sess_stat = server_context.session_stats()
4349 self.assertEqual(sess_stat['accept'], 1)
4350 self.assertEqual(sess_stat['hits'], 0)
Giampaolo Rodola'915d1412014-06-11 03:54:30 +02004351
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004352 # reuse session
Christian Heimesa170fa12017-09-15 20:27:30 +02004353 stats = server_params_test(client_context, server_context,
4354 session=session, sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004355 sess_stat = server_context.session_stats()
4356 self.assertEqual(sess_stat['accept'], 2)
4357 self.assertEqual(sess_stat['hits'], 1)
4358 self.assertTrue(stats['session_reused'])
4359 session2 = stats['session']
4360 self.assertEqual(session2.id, session.id)
4361 self.assertEqual(session2, session)
4362 self.assertIsNot(session2, session)
4363 self.assertGreaterEqual(session2.time, session.time)
4364 self.assertGreaterEqual(session2.timeout, session.timeout)
Christian Heimes99a65702016-09-10 23:44:53 +02004365
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004366 # another one without session
Christian Heimesa170fa12017-09-15 20:27:30 +02004367 stats = server_params_test(client_context, server_context,
4368 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004369 self.assertFalse(stats['session_reused'])
4370 session3 = stats['session']
4371 self.assertNotEqual(session3.id, session.id)
4372 self.assertNotEqual(session3, session)
4373 sess_stat = server_context.session_stats()
4374 self.assertEqual(sess_stat['accept'], 3)
4375 self.assertEqual(sess_stat['hits'], 1)
Christian Heimes99a65702016-09-10 23:44:53 +02004376
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004377 # reuse session again
Christian Heimesa170fa12017-09-15 20:27:30 +02004378 stats = server_params_test(client_context, server_context,
4379 session=session, sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004380 self.assertTrue(stats['session_reused'])
4381 session4 = stats['session']
4382 self.assertEqual(session4.id, session.id)
4383 self.assertEqual(session4, session)
4384 self.assertGreaterEqual(session4.time, session.time)
4385 self.assertGreaterEqual(session4.timeout, session.timeout)
4386 sess_stat = server_context.session_stats()
4387 self.assertEqual(sess_stat['accept'], 4)
4388 self.assertEqual(sess_stat['hits'], 2)
Christian Heimes99a65702016-09-10 23:44:53 +02004389
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004390 def test_session_handling(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004391 client_context, server_context, hostname = testing_context()
4392 client_context2, _, _ = testing_context()
Christian Heimes99a65702016-09-10 23:44:53 +02004393
Christian Heimes05d9fe32018-02-27 08:55:39 +01004394 # TODO: session reuse does not work with TLSv1.3
Miss Islington (bot)4becc562021-06-13 05:07:00 -07004395 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
4396 client_context2.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimescb5b68a2017-09-07 18:07:00 -07004397
Christian Heimesa170fa12017-09-15 20:27:30 +02004398 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004399 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02004400 with client_context.wrap_socket(socket.socket(),
4401 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004402 # session is None before handshake
4403 self.assertEqual(s.session, None)
4404 self.assertEqual(s.session_reused, None)
4405 s.connect((HOST, server.port))
4406 session = s.session
4407 self.assertTrue(session)
4408 with self.assertRaises(TypeError) as e:
4409 s.session = object
Ned Deily4531ec72018-06-11 20:26:28 -04004410 self.assertEqual(str(e.exception), 'Value is not a SSLSession.')
Christian Heimes99a65702016-09-10 23:44:53 +02004411
Christian Heimesa170fa12017-09-15 20:27:30 +02004412 with client_context.wrap_socket(socket.socket(),
4413 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004414 s.connect((HOST, server.port))
4415 # cannot set session after handshake
4416 with self.assertRaises(ValueError) as e:
4417 s.session = session
4418 self.assertEqual(str(e.exception),
4419 'Cannot set session after handshake.')
Christian Heimes99a65702016-09-10 23:44:53 +02004420
Christian Heimesa170fa12017-09-15 20:27:30 +02004421 with client_context.wrap_socket(socket.socket(),
4422 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004423 # can set session before handshake and before the
4424 # connection was established
4425 s.session = session
4426 s.connect((HOST, server.port))
4427 self.assertEqual(s.session.id, session.id)
4428 self.assertEqual(s.session, session)
4429 self.assertEqual(s.session_reused, True)
Christian Heimes99a65702016-09-10 23:44:53 +02004430
Christian Heimesa170fa12017-09-15 20:27:30 +02004431 with client_context2.wrap_socket(socket.socket(),
4432 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004433 # cannot re-use session with a different SSLContext
4434 with self.assertRaises(ValueError) as e:
Christian Heimes99a65702016-09-10 23:44:53 +02004435 s.session = session
4436 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004437 self.assertEqual(str(e.exception),
4438 'Session refers to a different SSLContext.')
Christian Heimes99a65702016-09-10 23:44:53 +02004439
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01004440
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02004441@unittest.skipUnless(has_tls_version('TLSv1_3'), "Test needs TLS 1.3")
Christian Heimes9fb051f2018-09-23 08:32:31 +02004442class TestPostHandshakeAuth(unittest.TestCase):
4443 def test_pha_setter(self):
4444 protocols = [
Christian Heimes2875c602021-04-19 07:27:10 +02004445 ssl.PROTOCOL_TLS_SERVER, ssl.PROTOCOL_TLS_CLIENT
Christian Heimes9fb051f2018-09-23 08:32:31 +02004446 ]
4447 for protocol in protocols:
4448 ctx = ssl.SSLContext(protocol)
4449 self.assertEqual(ctx.post_handshake_auth, False)
4450
4451 ctx.post_handshake_auth = True
4452 self.assertEqual(ctx.post_handshake_auth, True)
4453
4454 ctx.verify_mode = ssl.CERT_REQUIRED
4455 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
4456 self.assertEqual(ctx.post_handshake_auth, True)
4457
4458 ctx.post_handshake_auth = False
4459 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
4460 self.assertEqual(ctx.post_handshake_auth, False)
4461
4462 ctx.verify_mode = ssl.CERT_OPTIONAL
4463 ctx.post_handshake_auth = True
4464 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
4465 self.assertEqual(ctx.post_handshake_auth, True)
4466
4467 def test_pha_required(self):
4468 client_context, server_context, hostname = testing_context()
4469 server_context.post_handshake_auth = True
4470 server_context.verify_mode = ssl.CERT_REQUIRED
4471 client_context.post_handshake_auth = True
4472 client_context.load_cert_chain(SIGNED_CERTFILE)
4473
4474 server = ThreadedEchoServer(context=server_context, chatty=False)
4475 with server:
4476 with client_context.wrap_socket(socket.socket(),
4477 server_hostname=hostname) as s:
4478 s.connect((HOST, server.port))
4479 s.write(b'HASCERT')
4480 self.assertEqual(s.recv(1024), b'FALSE\n')
4481 s.write(b'PHA')
4482 self.assertEqual(s.recv(1024), b'OK\n')
4483 s.write(b'HASCERT')
4484 self.assertEqual(s.recv(1024), b'TRUE\n')
4485 # PHA method just returns true when cert is already available
4486 s.write(b'PHA')
4487 self.assertEqual(s.recv(1024), b'OK\n')
4488 s.write(b'GETCERT')
4489 cert_text = s.recv(4096).decode('us-ascii')
4490 self.assertIn('Python Software Foundation CA', cert_text)
4491
4492 def test_pha_required_nocert(self):
4493 client_context, server_context, hostname = testing_context()
4494 server_context.post_handshake_auth = True
4495 server_context.verify_mode = ssl.CERT_REQUIRED
4496 client_context.post_handshake_auth = True
4497
Christian Heimesc8666cf2021-04-24 09:17:54 +02004498 def msg_cb(conn, direction, version, content_type, msg_type, data):
4499 if support.verbose and content_type == _TLSContentType.ALERT:
4500 info = (conn, direction, version, content_type, msg_type, data)
4501 sys.stdout.write(f"TLS: {info!r}\n")
4502
4503 server_context._msg_callback = msg_cb
4504 client_context._msg_callback = msg_cb
4505
4506 server = ThreadedEchoServer(context=server_context, chatty=True)
4507 with server:
4508 with client_context.wrap_socket(socket.socket(),
Miss Islington (bot)d2ab15f2021-06-03 13:15:15 -07004509 server_hostname=hostname,
4510 suppress_ragged_eofs=False) as s:
Christian Heimesc8666cf2021-04-24 09:17:54 +02004511 s.connect((HOST, server.port))
4512 s.write(b'PHA')
Christian Heimesce9a0642021-04-24 15:08:13 +02004513 # test sometimes fails with EOF error. Test passes as long as
4514 # server aborts connection with an error.
Christian Heimesc8666cf2021-04-24 09:17:54 +02004515 with self.assertRaisesRegex(
4516 ssl.SSLError,
Christian Heimesce9a0642021-04-24 15:08:13 +02004517 '(certificate required|EOF occurred)'
Christian Heimesc8666cf2021-04-24 09:17:54 +02004518 ):
Victor Stinner73ea5462019-07-09 14:33:49 +02004519 # receive CertificateRequest
Miss Islington (bot)e5e93e62021-06-02 16:48:40 -07004520 data = s.recv(1024)
Miss Islington (bot)e5e93e62021-06-02 16:48:40 -07004521 self.assertEqual(data, b'OK\n')
4522
Victor Stinner73ea5462019-07-09 14:33:49 +02004523 # send empty Certificate + Finish
4524 s.write(b'HASCERT')
Miss Islington (bot)e5e93e62021-06-02 16:48:40 -07004525
Victor Stinner73ea5462019-07-09 14:33:49 +02004526 # receive alert
Miss Islington (bot)d2ab15f2021-06-03 13:15:15 -07004527 s.recv(1024)
Christian Heimes9fb051f2018-09-23 08:32:31 +02004528
4529 def test_pha_optional(self):
4530 if support.verbose:
4531 sys.stdout.write("\n")
4532
4533 client_context, server_context, hostname = testing_context()
4534 server_context.post_handshake_auth = True
4535 server_context.verify_mode = ssl.CERT_REQUIRED
4536 client_context.post_handshake_auth = True
4537 client_context.load_cert_chain(SIGNED_CERTFILE)
4538
4539 # check CERT_OPTIONAL
4540 server_context.verify_mode = ssl.CERT_OPTIONAL
4541 server = ThreadedEchoServer(context=server_context, chatty=False)
4542 with server:
4543 with client_context.wrap_socket(socket.socket(),
4544 server_hostname=hostname) as s:
4545 s.connect((HOST, server.port))
4546 s.write(b'HASCERT')
4547 self.assertEqual(s.recv(1024), b'FALSE\n')
4548 s.write(b'PHA')
4549 self.assertEqual(s.recv(1024), b'OK\n')
4550 s.write(b'HASCERT')
4551 self.assertEqual(s.recv(1024), b'TRUE\n')
4552
4553 def test_pha_optional_nocert(self):
4554 if support.verbose:
4555 sys.stdout.write("\n")
4556
4557 client_context, server_context, hostname = testing_context()
4558 server_context.post_handshake_auth = True
4559 server_context.verify_mode = ssl.CERT_OPTIONAL
4560 client_context.post_handshake_auth = True
4561
4562 server = ThreadedEchoServer(context=server_context, chatty=False)
4563 with server:
4564 with client_context.wrap_socket(socket.socket(),
4565 server_hostname=hostname) as s:
4566 s.connect((HOST, server.port))
4567 s.write(b'HASCERT')
4568 self.assertEqual(s.recv(1024), b'FALSE\n')
4569 s.write(b'PHA')
4570 self.assertEqual(s.recv(1024), b'OK\n')
penguindustin96466302019-05-06 14:57:17 -04004571 # optional doesn't fail when client does not have a cert
Christian Heimes9fb051f2018-09-23 08:32:31 +02004572 s.write(b'HASCERT')
4573 self.assertEqual(s.recv(1024), b'FALSE\n')
4574
4575 def test_pha_no_pha_client(self):
4576 client_context, server_context, hostname = testing_context()
4577 server_context.post_handshake_auth = True
4578 server_context.verify_mode = ssl.CERT_REQUIRED
4579 client_context.load_cert_chain(SIGNED_CERTFILE)
4580
4581 server = ThreadedEchoServer(context=server_context, chatty=False)
4582 with server:
4583 with client_context.wrap_socket(socket.socket(),
4584 server_hostname=hostname) as s:
4585 s.connect((HOST, server.port))
4586 with self.assertRaisesRegex(ssl.SSLError, 'not server'):
4587 s.verify_client_post_handshake()
4588 s.write(b'PHA')
4589 self.assertIn(b'extension not received', s.recv(1024))
4590
4591 def test_pha_no_pha_server(self):
4592 # server doesn't have PHA enabled, cert is requested in handshake
4593 client_context, server_context, hostname = testing_context()
4594 server_context.verify_mode = ssl.CERT_REQUIRED
4595 client_context.post_handshake_auth = True
4596 client_context.load_cert_chain(SIGNED_CERTFILE)
4597
4598 server = ThreadedEchoServer(context=server_context, chatty=False)
4599 with server:
4600 with client_context.wrap_socket(socket.socket(),
4601 server_hostname=hostname) as s:
4602 s.connect((HOST, server.port))
4603 s.write(b'HASCERT')
4604 self.assertEqual(s.recv(1024), b'TRUE\n')
4605 # PHA doesn't fail if there is already a cert
4606 s.write(b'PHA')
4607 self.assertEqual(s.recv(1024), b'OK\n')
4608 s.write(b'HASCERT')
4609 self.assertEqual(s.recv(1024), b'TRUE\n')
4610
4611 def test_pha_not_tls13(self):
4612 # TLS 1.2
4613 client_context, server_context, hostname = testing_context()
4614 server_context.verify_mode = ssl.CERT_REQUIRED
4615 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
4616 client_context.post_handshake_auth = True
4617 client_context.load_cert_chain(SIGNED_CERTFILE)
4618
4619 server = ThreadedEchoServer(context=server_context, chatty=False)
4620 with server:
4621 with client_context.wrap_socket(socket.socket(),
4622 server_hostname=hostname) as s:
4623 s.connect((HOST, server.port))
4624 # PHA fails for TLS != 1.3
4625 s.write(b'PHA')
4626 self.assertIn(b'WRONG_SSL_VERSION', s.recv(1024))
4627
Christian Heimesf0f59302019-07-01 08:29:17 +02004628 def test_bpo37428_pha_cert_none(self):
4629 # verify that post_handshake_auth does not implicitly enable cert
4630 # validation.
4631 hostname = SIGNED_CERTFILE_HOSTNAME
4632 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4633 client_context.post_handshake_auth = True
4634 client_context.load_cert_chain(SIGNED_CERTFILE)
4635 # no cert validation and CA on client side
4636 client_context.check_hostname = False
4637 client_context.verify_mode = ssl.CERT_NONE
4638
4639 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
4640 server_context.load_cert_chain(SIGNED_CERTFILE)
4641 server_context.load_verify_locations(SIGNING_CA)
4642 server_context.post_handshake_auth = True
4643 server_context.verify_mode = ssl.CERT_REQUIRED
4644
4645 server = ThreadedEchoServer(context=server_context, chatty=False)
4646 with server:
4647 with client_context.wrap_socket(socket.socket(),
4648 server_hostname=hostname) as s:
4649 s.connect((HOST, server.port))
4650 s.write(b'HASCERT')
4651 self.assertEqual(s.recv(1024), b'FALSE\n')
4652 s.write(b'PHA')
4653 self.assertEqual(s.recv(1024), b'OK\n')
4654 s.write(b'HASCERT')
4655 self.assertEqual(s.recv(1024), b'TRUE\n')
4656 # server cert has not been validated
4657 self.assertEqual(s.getpeercert(), {})
4658
Christian Heimes666991f2021-04-26 15:01:40 +02004659 def test_internal_chain_client(self):
4660 client_context, server_context, hostname = testing_context(
4661 server_chain=False
4662 )
4663 server = ThreadedEchoServer(context=server_context, chatty=False)
4664 with server:
4665 with client_context.wrap_socket(
4666 socket.socket(),
4667 server_hostname=hostname
4668 ) as s:
4669 s.connect((HOST, server.port))
4670 vc = s._sslobj.get_verified_chain()
4671 self.assertEqual(len(vc), 2)
4672 ee, ca = vc
4673 uvc = s._sslobj.get_unverified_chain()
4674 self.assertEqual(len(uvc), 1)
4675
4676 self.assertEqual(ee, uvc[0])
4677 self.assertEqual(hash(ee), hash(uvc[0]))
4678 self.assertEqual(repr(ee), repr(uvc[0]))
4679
4680 self.assertNotEqual(ee, ca)
4681 self.assertNotEqual(hash(ee), hash(ca))
4682 self.assertNotEqual(repr(ee), repr(ca))
4683 self.assertNotEqual(ee.get_info(), ca.get_info())
4684 self.assertIn("CN=localhost", repr(ee))
4685 self.assertIn("CN=our-ca-server", repr(ca))
4686
4687 pem = ee.public_bytes(_ssl.ENCODING_PEM)
4688 der = ee.public_bytes(_ssl.ENCODING_DER)
4689 self.assertIsInstance(pem, str)
4690 self.assertIn("-----BEGIN CERTIFICATE-----", pem)
4691 self.assertIsInstance(der, bytes)
4692 self.assertEqual(
4693 ssl.PEM_cert_to_DER_cert(pem), der
4694 )
4695
4696 def test_internal_chain_server(self):
4697 client_context, server_context, hostname = testing_context()
4698 client_context.load_cert_chain(SIGNED_CERTFILE)
4699 server_context.verify_mode = ssl.CERT_REQUIRED
4700 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
4701
4702 server = ThreadedEchoServer(context=server_context, chatty=False)
4703 with server:
4704 with client_context.wrap_socket(
4705 socket.socket(),
4706 server_hostname=hostname
4707 ) as s:
4708 s.connect((HOST, server.port))
4709 s.write(b'VERIFIEDCHAIN\n')
4710 res = s.recv(1024)
4711 self.assertEqual(res, b'\x02\n')
4712 s.write(b'UNVERIFIEDCHAIN\n')
4713 res = s.recv(1024)
4714 self.assertEqual(res, b'\x02\n')
4715
Christian Heimes9fb051f2018-09-23 08:32:31 +02004716
Christian Heimesc7f70692019-05-31 11:44:05 +02004717HAS_KEYLOG = hasattr(ssl.SSLContext, 'keylog_filename')
4718requires_keylog = unittest.skipUnless(
4719 HAS_KEYLOG, 'test requires OpenSSL 1.1.1 with keylog callback')
4720
4721class TestSSLDebug(unittest.TestCase):
4722
Hai Shia7f5d932020-08-04 00:41:24 +08004723 def keylog_lines(self, fname=os_helper.TESTFN):
Christian Heimesc7f70692019-05-31 11:44:05 +02004724 with open(fname) as f:
4725 return len(list(f))
4726
4727 @requires_keylog
Paul Monsonf3550692019-06-19 13:09:54 -07004728 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004729 def test_keylog_defaults(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004730 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004731 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4732 self.assertEqual(ctx.keylog_filename, None)
4733
Hai Shia7f5d932020-08-04 00:41:24 +08004734 self.assertFalse(os.path.isfile(os_helper.TESTFN))
4735 ctx.keylog_filename = os_helper.TESTFN
4736 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
4737 self.assertTrue(os.path.isfile(os_helper.TESTFN))
Christian Heimesc7f70692019-05-31 11:44:05 +02004738 self.assertEqual(self.keylog_lines(), 1)
4739
4740 ctx.keylog_filename = None
4741 self.assertEqual(ctx.keylog_filename, None)
4742
4743 with self.assertRaises((IsADirectoryError, PermissionError)):
4744 # Windows raises PermissionError
4745 ctx.keylog_filename = os.path.dirname(
Hai Shia7f5d932020-08-04 00:41:24 +08004746 os.path.abspath(os_helper.TESTFN))
Christian Heimesc7f70692019-05-31 11:44:05 +02004747
4748 with self.assertRaises(TypeError):
4749 ctx.keylog_filename = 1
4750
4751 @requires_keylog
Paul Monsonf3550692019-06-19 13:09:54 -07004752 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004753 def test_keylog_filename(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004754 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004755 client_context, server_context, hostname = testing_context()
4756
Hai Shia7f5d932020-08-04 00:41:24 +08004757 client_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004758 server = ThreadedEchoServer(context=server_context, chatty=False)
4759 with server:
4760 with client_context.wrap_socket(socket.socket(),
4761 server_hostname=hostname) as s:
4762 s.connect((HOST, server.port))
4763 # header, 5 lines for TLS 1.3
4764 self.assertEqual(self.keylog_lines(), 6)
4765
4766 client_context.keylog_filename = None
Hai Shia7f5d932020-08-04 00:41:24 +08004767 server_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004768 server = ThreadedEchoServer(context=server_context, chatty=False)
4769 with server:
4770 with client_context.wrap_socket(socket.socket(),
4771 server_hostname=hostname) as s:
4772 s.connect((HOST, server.port))
4773 self.assertGreaterEqual(self.keylog_lines(), 11)
4774
Hai Shia7f5d932020-08-04 00:41:24 +08004775 client_context.keylog_filename = os_helper.TESTFN
4776 server_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004777 server = ThreadedEchoServer(context=server_context, chatty=False)
4778 with server:
4779 with client_context.wrap_socket(socket.socket(),
4780 server_hostname=hostname) as s:
4781 s.connect((HOST, server.port))
4782 self.assertGreaterEqual(self.keylog_lines(), 21)
4783
4784 client_context.keylog_filename = None
4785 server_context.keylog_filename = None
4786
4787 @requires_keylog
4788 @unittest.skipIf(sys.flags.ignore_environment,
4789 "test is not compatible with ignore_environment")
Paul Monsonf3550692019-06-19 13:09:54 -07004790 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004791 def test_keylog_env(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004792 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004793 with unittest.mock.patch.dict(os.environ):
Hai Shia7f5d932020-08-04 00:41:24 +08004794 os.environ['SSLKEYLOGFILE'] = os_helper.TESTFN
4795 self.assertEqual(os.environ['SSLKEYLOGFILE'], os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004796
4797 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4798 self.assertEqual(ctx.keylog_filename, None)
4799
4800 ctx = ssl.create_default_context()
Hai Shia7f5d932020-08-04 00:41:24 +08004801 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004802
4803 ctx = ssl._create_stdlib_context()
Hai Shia7f5d932020-08-04 00:41:24 +08004804 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004805
4806 def test_msg_callback(self):
4807 client_context, server_context, hostname = testing_context()
4808
4809 def msg_cb(conn, direction, version, content_type, msg_type, data):
4810 pass
4811
4812 self.assertIs(client_context._msg_callback, None)
4813 client_context._msg_callback = msg_cb
4814 self.assertIs(client_context._msg_callback, msg_cb)
4815 with self.assertRaises(TypeError):
4816 client_context._msg_callback = object()
4817
4818 def test_msg_callback_tls12(self):
4819 client_context, server_context, hostname = testing_context()
Miss Islington (bot)4becc562021-06-13 05:07:00 -07004820 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesc7f70692019-05-31 11:44:05 +02004821
4822 msg = []
4823
4824 def msg_cb(conn, direction, version, content_type, msg_type, data):
4825 self.assertIsInstance(conn, ssl.SSLSocket)
4826 self.assertIsInstance(data, bytes)
4827 self.assertIn(direction, {'read', 'write'})
4828 msg.append((direction, version, content_type, msg_type))
4829
4830 client_context._msg_callback = msg_cb
4831
4832 server = ThreadedEchoServer(context=server_context, chatty=False)
4833 with server:
4834 with client_context.wrap_socket(socket.socket(),
4835 server_hostname=hostname) as s:
4836 s.connect((HOST, server.port))
4837
Christian Heimese35d1ba2019-06-03 20:40:15 +02004838 self.assertIn(
Christian Heimesc7f70692019-05-31 11:44:05 +02004839 ("read", TLSVersion.TLSv1_2, _TLSContentType.HANDSHAKE,
4840 _TLSMessageType.SERVER_KEY_EXCHANGE),
Christian Heimese35d1ba2019-06-03 20:40:15 +02004841 msg
4842 )
4843 self.assertIn(
Christian Heimesc7f70692019-05-31 11:44:05 +02004844 ("write", TLSVersion.TLSv1_2, _TLSContentType.CHANGE_CIPHER_SPEC,
4845 _TLSMessageType.CHANGE_CIPHER_SPEC),
Christian Heimese35d1ba2019-06-03 20:40:15 +02004846 msg
4847 )
Christian Heimesc7f70692019-05-31 11:44:05 +02004848
Christian Heimes77cde502021-03-21 16:13:09 +01004849 def test_msg_callback_deadlock_bpo43577(self):
4850 client_context, server_context, hostname = testing_context()
4851 server_context2 = testing_context()[1]
4852
4853 def msg_cb(conn, direction, version, content_type, msg_type, data):
4854 pass
4855
4856 def sni_cb(sock, servername, ctx):
4857 sock.context = server_context2
4858
4859 server_context._msg_callback = msg_cb
4860 server_context.sni_callback = sni_cb
4861
4862 server = ThreadedEchoServer(context=server_context, chatty=False)
4863 with server:
4864 with client_context.wrap_socket(socket.socket(),
4865 server_hostname=hostname) as s:
4866 s.connect((HOST, server.port))
4867 with client_context.wrap_socket(socket.socket(),
4868 server_hostname=hostname) as s:
4869 s.connect((HOST, server.port))
4870
Christian Heimesc7f70692019-05-31 11:44:05 +02004871
Thomas Woutersed03b412007-08-28 21:37:11 +00004872def test_main(verbose=False):
Antoine Pitrou15cee622010-08-04 16:45:21 +00004873 if support.verbose:
4874 plats = {
Antoine Pitrou15cee622010-08-04 16:45:21 +00004875 'Mac': platform.mac_ver,
4876 'Windows': platform.win32_ver,
4877 }
Petr Viktorin8b94b412018-05-16 11:51:18 -04004878 for name, func in plats.items():
4879 plat = func()
4880 if plat and plat[0]:
4881 plat = '%s %r' % (name, plat)
4882 break
4883 else:
4884 plat = repr(platform.platform())
Antoine Pitrou15cee622010-08-04 16:45:21 +00004885 print("test_ssl: testing with %r %r" %
4886 (ssl.OPENSSL_VERSION, ssl.OPENSSL_VERSION_INFO))
4887 print(" under %s" % plat)
Antoine Pitroud5323212010-10-22 18:19:07 +00004888 print(" HAS_SNI = %r" % ssl.HAS_SNI)
Antoine Pitrou609ef012013-03-29 18:09:06 +01004889 print(" OP_ALL = 0x%8x" % ssl.OP_ALL)
4890 try:
4891 print(" OP_NO_TLSv1_1 = 0x%8x" % ssl.OP_NO_TLSv1_1)
4892 except AttributeError:
4893 pass
Antoine Pitrou15cee622010-08-04 16:45:21 +00004894
Antoine Pitrou152efa22010-05-16 18:19:27 +00004895 for filename in [
Martin Panter3840b2a2016-03-27 01:53:46 +00004896 CERTFILE, BYTES_CERTFILE,
Antoine Pitrou152efa22010-05-16 18:19:27 +00004897 ONLYCERT, ONLYKEY, BYTES_ONLYCERT, BYTES_ONLYKEY,
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004898 SIGNED_CERTFILE, SIGNED_CERTFILE2, SIGNING_CA,
Antoine Pitrou152efa22010-05-16 18:19:27 +00004899 BADCERT, BADKEY, EMPTYCERT]:
4900 if not os.path.exists(filename):
4901 raise support.TestFailed("Can't read certificate file %r" % filename)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004902
Martin Panter3840b2a2016-03-27 01:53:46 +00004903 tests = [
4904 ContextTests, BasicSocketTests, SSLErrorTests, MemoryBIOTests,
Christian Heimes9d50ab52018-02-27 10:17:30 +01004905 SSLObjectTests, SimpleBackgroundTests, ThreadedTests,
Christian Heimesc7f70692019-05-31 11:44:05 +02004906 TestPostHandshakeAuth, TestSSLDebug
Martin Panter3840b2a2016-03-27 01:53:46 +00004907 ]
Thomas Woutersed03b412007-08-28 21:37:11 +00004908
Benjamin Petersonee8712c2008-05-20 21:35:26 +00004909 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00004910 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00004911
Hai Shie80697d2020-05-28 06:10:27 +08004912 thread_info = threading_helper.threading_setup()
Antoine Pitrou480a1242010-04-28 21:37:09 +00004913 try:
4914 support.run_unittest(*tests)
4915 finally:
Hai Shie80697d2020-05-28 06:10:27 +08004916 threading_helper.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00004917
4918if __name__ == "__main__":
4919 test_main()