blob: 873db6403d1a00caa19aa513dfab6d492232b924 [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}"
Miss Islington (bot)251d2ea2021-12-17 07:38:11 -0800542 if major >= 3:
543 # 3.x uses 0xMNN00PP0L
544 openssl_ver = f"OpenSSL {major:d}.{minor:d}.{patch:d}"
545 else:
546 openssl_ver = f"OpenSSL {major:d}.{minor:d}.{fix:d}"
Christian Heimesd37b74f2021-04-19 08:31:29 +0200547 self.assertTrue(
548 s.startswith((openssl_ver, libressl_ver)),
549 (s, t, hex(n))
550 )
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000551
Antoine Pitrou9d543662010-04-23 23:10:32 +0000552 @support.cpython_only
553 def test_refcycle(self):
554 # Issue #7943: an SSL object doesn't create reference cycles with
555 # itself.
556 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200557 ss = test_wrap_socket(s)
Antoine Pitrou9d543662010-04-23 23:10:32 +0000558 wr = weakref.ref(ss)
Hai Shia7f5d932020-08-04 00:41:24 +0800559 with warnings_helper.check_warnings(("", ResourceWarning)):
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100560 del ss
Victor Stinnere0b75b72016-03-21 17:26:04 +0100561 self.assertEqual(wr(), None)
Antoine Pitrou9d543662010-04-23 23:10:32 +0000562
Antoine Pitroua468adc2010-09-14 14:43:44 +0000563 def test_wrapped_unconnected(self):
564 # Methods on an unconnected SSLSocket propagate the original
Andrew Svetlov0832af62012-12-18 23:10:48 +0200565 # OSError raise by the underlying socket object.
Antoine Pitroua468adc2010-09-14 14:43:44 +0000566 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200567 with test_wrap_socket(s) as ss:
Antoine Pitroue9bb4732013-01-12 21:56:56 +0100568 self.assertRaises(OSError, ss.recv, 1)
569 self.assertRaises(OSError, ss.recv_into, bytearray(b'x'))
570 self.assertRaises(OSError, ss.recvfrom, 1)
571 self.assertRaises(OSError, ss.recvfrom_into, bytearray(b'x'), 1)
572 self.assertRaises(OSError, ss.send, b'x')
573 self.assertRaises(OSError, ss.sendto, b'x', ('0.0.0.0', 0))
Serhiy Storchaka42b1d612018-12-06 22:36:55 +0200574 self.assertRaises(NotImplementedError, ss.dup)
Christian Heimes141c5e82018-02-24 21:10:57 +0100575 self.assertRaises(NotImplementedError, ss.sendmsg,
576 [b'x'], (), 0, ('0.0.0.0', 0))
Serhiy Storchaka42b1d612018-12-06 22:36:55 +0200577 self.assertRaises(NotImplementedError, ss.recvmsg, 100)
578 self.assertRaises(NotImplementedError, ss.recvmsg_into,
579 [bytearray(100)])
Antoine Pitroua468adc2010-09-14 14:43:44 +0000580
Antoine Pitrou40f08742010-04-24 22:04:40 +0000581 def test_timeout(self):
582 # Issue #8524: when creating an SSL socket, the timeout of the
583 # original socket should be retained.
584 for timeout in (None, 0.0, 5.0):
585 s = socket.socket(socket.AF_INET)
586 s.settimeout(timeout)
Christian Heimesd0486372016-09-10 23:23:33 +0200587 with test_wrap_socket(s) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100588 self.assertEqual(timeout, ss.gettimeout())
Antoine Pitrou40f08742010-04-24 22:04:40 +0000589
Miss Islington (bot)4becc562021-06-13 05:07:00 -0700590 def test_openssl111_deprecations(self):
591 options = [
592 ssl.OP_NO_TLSv1,
593 ssl.OP_NO_TLSv1_1,
594 ssl.OP_NO_TLSv1_2,
595 ssl.OP_NO_TLSv1_3
596 ]
597 protocols = [
598 ssl.PROTOCOL_TLSv1,
599 ssl.PROTOCOL_TLSv1_1,
600 ssl.PROTOCOL_TLSv1_2,
601 ssl.PROTOCOL_TLS
602 ]
603 versions = [
604 ssl.TLSVersion.SSLv3,
605 ssl.TLSVersion.TLSv1,
606 ssl.TLSVersion.TLSv1_1,
607 ]
608
609 for option in options:
610 with self.subTest(option=option):
611 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
612 with self.assertWarns(DeprecationWarning) as cm:
613 ctx.options |= option
614 self.assertEqual(
Miss Islington (bot)08f2b9d2021-06-17 03:00:56 -0700615 'ssl.OP_NO_SSL*/ssl.OP_NO_TLS* options are deprecated',
Miss Islington (bot)4becc562021-06-13 05:07:00 -0700616 str(cm.warning)
617 )
618
619 for protocol in protocols:
620 with self.subTest(protocol=protocol):
621 with self.assertWarns(DeprecationWarning) as cm:
622 ssl.SSLContext(protocol)
623 self.assertEqual(
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700624 f'ssl.{protocol.name} is deprecated',
Miss Islington (bot)4becc562021-06-13 05:07:00 -0700625 str(cm.warning)
626 )
627
628 for version in versions:
629 with self.subTest(version=version):
630 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
631 with self.assertWarns(DeprecationWarning) as cm:
632 ctx.minimum_version = version
633 self.assertEqual(
Ethan Furman9bf7c2d2021-07-03 21:08:42 -0700634 f'ssl.{version!s} is deprecated',
Miss Islington (bot)4becc562021-06-13 05:07:00 -0700635 str(cm.warning)
636 )
637
Christian Heimes2875c602021-04-19 07:27:10 +0200638 @ignore_deprecation
Christian Heimesd0486372016-09-10 23:23:33 +0200639 def test_errors_sslwrap(self):
Giampaolo Rodolà745ab382010-08-29 19:25:49 +0000640 sock = socket.socket()
Ezio Melottied3a7d22010-12-01 02:32:32 +0000641 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000642 "certfile must be specified",
643 ssl.wrap_socket, sock, keyfile=CERTFILE)
Ezio Melottied3a7d22010-12-01 02:32:32 +0000644 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000645 "certfile must be specified for server-side operations",
646 ssl.wrap_socket, sock, server_side=True)
Ezio Melottied3a7d22010-12-01 02:32:32 +0000647 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000648 "certfile must be specified for server-side operations",
Christian Heimesd0486372016-09-10 23:23:33 +0200649 ssl.wrap_socket, sock, server_side=True, certfile="")
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100650 with ssl.wrap_socket(sock, server_side=True, certfile=CERTFILE) as s:
651 self.assertRaisesRegex(ValueError, "can't connect in server-side mode",
Christian Heimesd0486372016-09-10 23:23:33 +0200652 s.connect, (HOST, 8080))
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, certfile=NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +0000656 self.assertEqual(cm.exception.errno, errno.ENOENT)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200657 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000658 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000659 ssl.wrap_socket(sock,
660 certfile=CERTFILE, keyfile=NONEXISTINGCERT)
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000661 self.assertEqual(cm.exception.errno, errno.ENOENT)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200662 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000663 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000664 ssl.wrap_socket(sock,
665 certfile=NONEXISTINGCERT, keyfile=NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +0000666 self.assertEqual(cm.exception.errno, errno.ENOENT)
Giampaolo Rodolà745ab382010-08-29 19:25:49 +0000667
Martin Panter3464ea22016-02-01 21:58:11 +0000668 def bad_cert_test(self, certfile):
669 """Check that trying to use the given client certificate fails"""
670 certfile = os.path.join(os.path.dirname(__file__) or os.curdir,
671 certfile)
672 sock = socket.socket()
673 self.addCleanup(sock.close)
674 with self.assertRaises(ssl.SSLError):
Christian Heimesd0486372016-09-10 23:23:33 +0200675 test_wrap_socket(sock,
Christian Heimesa170fa12017-09-15 20:27:30 +0200676 certfile=certfile)
Martin Panter3464ea22016-02-01 21:58:11 +0000677
678 def test_empty_cert(self):
679 """Wrapping with an empty cert file"""
680 self.bad_cert_test("nullcert.pem")
681
682 def test_malformed_cert(self):
683 """Wrapping with a badly formatted certificate (syntax error)"""
684 self.bad_cert_test("badcert.pem")
685
686 def test_malformed_key(self):
687 """Wrapping with a badly formatted key (syntax error)"""
688 self.bad_cert_test("badkey.pem")
689
Christian Heimes2875c602021-04-19 07:27:10 +0200690 @ignore_deprecation
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000691 def test_match_hostname(self):
692 def ok(cert, hostname):
693 ssl.match_hostname(cert, hostname)
694 def fail(cert, hostname):
695 self.assertRaises(ssl.CertificateError,
696 ssl.match_hostname, cert, hostname)
697
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100698 # -- Hostname matching --
699
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000700 cert = {'subject': ((('commonName', 'example.com'),),)}
701 ok(cert, 'example.com')
702 ok(cert, 'ExAmple.cOm')
703 fail(cert, 'www.example.com')
704 fail(cert, '.example.com')
705 fail(cert, 'example.org')
706 fail(cert, 'exampleXcom')
707
708 cert = {'subject': ((('commonName', '*.a.com'),),)}
709 ok(cert, 'foo.a.com')
710 fail(cert, 'bar.foo.a.com')
711 fail(cert, 'a.com')
712 fail(cert, 'Xa.com')
713 fail(cert, '.a.com')
714
Mandeep Singhede2ac92017-11-27 04:01:27 +0530715 # only match wildcards when they are the only thing
716 # in left-most segment
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000717 cert = {'subject': ((('commonName', 'f*.com'),),)}
Mandeep Singhede2ac92017-11-27 04:01:27 +0530718 fail(cert, 'foo.com')
719 fail(cert, 'f.com')
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000720 fail(cert, 'bar.com')
721 fail(cert, 'foo.a.com')
722 fail(cert, 'bar.foo.com')
723
Christian Heimes824f7f32013-08-17 00:54:47 +0200724 # NULL bytes are bad, CVE-2013-4073
725 cert = {'subject': ((('commonName',
726 'null.python.org\x00example.org'),),)}
727 ok(cert, 'null.python.org\x00example.org') # or raise an error?
728 fail(cert, 'example.org')
729 fail(cert, 'null.python.org')
730
Georg Brandl72c98d32013-10-27 07:16:53 +0100731 # error cases with wildcards
732 cert = {'subject': ((('commonName', '*.*.a.com'),),)}
733 fail(cert, 'bar.foo.a.com')
734 fail(cert, 'a.com')
735 fail(cert, 'Xa.com')
736 fail(cert, '.a.com')
737
738 cert = {'subject': ((('commonName', 'a.*.com'),),)}
739 fail(cert, 'a.foo.com')
740 fail(cert, 'a..com')
741 fail(cert, 'a.com')
742
743 # wildcard doesn't match IDNA prefix 'xn--'
744 idna = 'püthon.python.org'.encode("idna").decode("ascii")
745 cert = {'subject': ((('commonName', idna),),)}
746 ok(cert, idna)
747 cert = {'subject': ((('commonName', 'x*.python.org'),),)}
748 fail(cert, idna)
749 cert = {'subject': ((('commonName', 'xn--p*.python.org'),),)}
750 fail(cert, idna)
751
752 # wildcard in first fragment and IDNA A-labels in sequent fragments
753 # are supported.
754 idna = 'www*.pythön.org'.encode("idna").decode("ascii")
755 cert = {'subject': ((('commonName', idna),),)}
Mandeep Singhede2ac92017-11-27 04:01:27 +0530756 fail(cert, 'www.pythön.org'.encode("idna").decode("ascii"))
757 fail(cert, 'www1.pythön.org'.encode("idna").decode("ascii"))
Georg Brandl72c98d32013-10-27 07:16:53 +0100758 fail(cert, 'ftp.pythön.org'.encode("idna").decode("ascii"))
759 fail(cert, 'pythön.org'.encode("idna").decode("ascii"))
760
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000761 # Slightly fake real-world example
762 cert = {'notAfter': 'Jun 26 21:41:46 2011 GMT',
763 'subject': ((('commonName', 'linuxfrz.org'),),),
764 'subjectAltName': (('DNS', 'linuxfr.org'),
765 ('DNS', 'linuxfr.com'),
766 ('othername', '<unsupported>'))}
767 ok(cert, 'linuxfr.org')
768 ok(cert, 'linuxfr.com')
769 # Not a "DNS" entry
770 fail(cert, '<unsupported>')
771 # When there is a subjectAltName, commonName isn't used
772 fail(cert, 'linuxfrz.org')
773
774 # A pristine real-world example
775 cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT',
776 'subject': ((('countryName', 'US'),),
777 (('stateOrProvinceName', 'California'),),
778 (('localityName', 'Mountain View'),),
779 (('organizationName', 'Google Inc'),),
780 (('commonName', 'mail.google.com'),))}
781 ok(cert, 'mail.google.com')
782 fail(cert, 'gmail.com')
783 # Only commonName is considered
784 fail(cert, 'California')
785
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100786 # -- IPv4 matching --
787 cert = {'subject': ((('commonName', 'example.com'),),),
788 'subjectAltName': (('DNS', 'example.com'),
789 ('IP Address', '10.11.12.13'),
Christian Heimes477b1b22019-07-02 20:39:42 +0200790 ('IP Address', '14.15.16.17'),
791 ('IP Address', '127.0.0.1'))}
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100792 ok(cert, '10.11.12.13')
793 ok(cert, '14.15.16.17')
Christian Heimes477b1b22019-07-02 20:39:42 +0200794 # socket.inet_ntoa(socket.inet_aton('127.1')) == '127.0.0.1'
795 fail(cert, '127.1')
796 fail(cert, '14.15.16.17 ')
797 fail(cert, '14.15.16.17 extra data')
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100798 fail(cert, '14.15.16.18')
799 fail(cert, 'example.net')
800
801 # -- IPv6 matching --
Serhiy Storchaka16994912020-04-25 10:06:29 +0300802 if socket_helper.IPV6_ENABLED:
Christian Heimesaef12832018-02-24 14:35:56 +0100803 cert = {'subject': ((('commonName', 'example.com'),),),
804 'subjectAltName': (
805 ('DNS', 'example.com'),
806 ('IP Address', '2001:0:0:0:0:0:0:CAFE\n'),
807 ('IP Address', '2003:0:0:0:0:0:0:BABA\n'))}
808 ok(cert, '2001::cafe')
809 ok(cert, '2003::baba')
Christian Heimes477b1b22019-07-02 20:39:42 +0200810 fail(cert, '2003::baba ')
811 fail(cert, '2003::baba extra data')
Christian Heimesaef12832018-02-24 14:35:56 +0100812 fail(cert, '2003::bebe')
813 fail(cert, 'example.net')
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100814
815 # -- Miscellaneous --
816
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000817 # Neither commonName nor subjectAltName
818 cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT',
819 'subject': ((('countryName', 'US'),),
820 (('stateOrProvinceName', 'California'),),
821 (('localityName', 'Mountain View'),),
822 (('organizationName', 'Google Inc'),))}
823 fail(cert, 'mail.google.com')
824
Antoine Pitrou1c86b442011-05-06 15:19:49 +0200825 # No DNS entry in subjectAltName but a commonName
826 cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT',
827 'subject': ((('countryName', 'US'),),
828 (('stateOrProvinceName', 'California'),),
829 (('localityName', 'Mountain View'),),
830 (('commonName', 'mail.google.com'),)),
831 'subjectAltName': (('othername', 'blabla'), )}
832 ok(cert, 'mail.google.com')
833
834 # No DNS entry subjectAltName and no commonName
835 cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT',
836 'subject': ((('countryName', 'US'),),
837 (('stateOrProvinceName', 'California'),),
838 (('localityName', 'Mountain View'),),
839 (('organizationName', 'Google Inc'),)),
840 'subjectAltName': (('othername', 'blabla'),)}
841 fail(cert, 'google.com')
842
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000843 # Empty cert / no cert
844 self.assertRaises(ValueError, ssl.match_hostname, None, 'example.com')
845 self.assertRaises(ValueError, ssl.match_hostname, {}, 'example.com')
846
Antoine Pitrou636f93c2013-05-18 17:56:42 +0200847 # Issue #17980: avoid denials of service by refusing more than one
848 # wildcard per fragment.
Christian Heimesaef12832018-02-24 14:35:56 +0100849 cert = {'subject': ((('commonName', 'a*b.example.com'),),)}
850 with self.assertRaisesRegex(
851 ssl.CertificateError,
852 "partial wildcards in leftmost label are not supported"):
853 ssl.match_hostname(cert, 'axxb.example.com')
854
855 cert = {'subject': ((('commonName', 'www.*.example.com'),),)}
856 with self.assertRaisesRegex(
857 ssl.CertificateError,
858 "wildcard can only be present in the leftmost label"):
859 ssl.match_hostname(cert, 'www.sub.example.com')
860
861 cert = {'subject': ((('commonName', 'a*b*.example.com'),),)}
862 with self.assertRaisesRegex(
863 ssl.CertificateError,
864 "too many wildcards"):
865 ssl.match_hostname(cert, 'axxbxxc.example.com')
866
867 cert = {'subject': ((('commonName', '*'),),)}
868 with self.assertRaisesRegex(
869 ssl.CertificateError,
870 "sole wildcard without additional labels are not support"):
871 ssl.match_hostname(cert, 'host')
872
873 cert = {'subject': ((('commonName', '*.com'),),)}
874 with self.assertRaisesRegex(
875 ssl.CertificateError,
876 r"hostname 'com' doesn't match '\*.com'"):
877 ssl.match_hostname(cert, 'com')
878
879 # extra checks for _inet_paton()
880 for invalid in ['1', '', '1.2.3', '256.0.0.1', '127.0.0.1/24']:
881 with self.assertRaises(ValueError):
882 ssl._inet_paton(invalid)
883 for ipaddr in ['127.0.0.1', '192.168.0.1']:
884 self.assertTrue(ssl._inet_paton(ipaddr))
Serhiy Storchaka16994912020-04-25 10:06:29 +0300885 if socket_helper.IPV6_ENABLED:
Christian Heimesaef12832018-02-24 14:35:56 +0100886 for ipaddr in ['::1', '2001:db8:85a3::8a2e:370:7334']:
887 self.assertTrue(ssl._inet_paton(ipaddr))
Antoine Pitrou636f93c2013-05-18 17:56:42 +0200888
Antoine Pitroud5323212010-10-22 18:19:07 +0000889 def test_server_side(self):
890 # server_hostname doesn't work for server sockets
Christian Heimesa170fa12017-09-15 20:27:30 +0200891 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroud2eca372010-10-29 23:41:37 +0000892 with socket.socket() as sock:
893 self.assertRaises(ValueError, ctx.wrap_socket, sock, True,
894 server_hostname="some.hostname")
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000895
Antoine Pitroud6494802011-07-21 01:11:30 +0200896 def test_unknown_channel_binding(self):
897 # should raise ValueError for unknown type
Giampaolo Rodolaeb7e29f2019-04-09 00:34:02 +0200898 s = socket.create_server(('127.0.0.1', 0))
Antoine Pitroub1fdf472014-10-05 20:41:53 +0200899 c = socket.socket(socket.AF_INET)
900 c.connect(s.getsockname())
Christian Heimesd0486372016-09-10 23:23:33 +0200901 with test_wrap_socket(c, do_handshake_on_connect=False) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100902 with self.assertRaises(ValueError):
903 ss.get_channel_binding("unknown-type")
Antoine Pitroub1fdf472014-10-05 20:41:53 +0200904 s.close()
Antoine Pitroud6494802011-07-21 01:11:30 +0200905
906 @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES,
907 "'tls-unique' channel binding not available")
908 def test_tls_unique_channel_binding(self):
909 # unconnected should return None for known type
910 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200911 with test_wrap_socket(s) 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 # the same for server-side
914 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200915 with test_wrap_socket(s, server_side=True, certfile=CERTFILE) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100916 self.assertIsNone(ss.get_channel_binding("tls-unique"))
Antoine Pitroud6494802011-07-21 01:11:30 +0200917
Benjamin Peterson36f7b972013-01-10 14:16:20 -0600918 def test_dealloc_warn(self):
Christian Heimesd0486372016-09-10 23:23:33 +0200919 ss = test_wrap_socket(socket.socket(socket.AF_INET))
Benjamin Peterson36f7b972013-01-10 14:16:20 -0600920 r = repr(ss)
921 with self.assertWarns(ResourceWarning) as cm:
922 ss = None
923 support.gc_collect()
924 self.assertIn(r, str(cm.warning.args[0]))
925
Christian Heimes6d7ad132013-06-09 18:02:55 +0200926 def test_get_default_verify_paths(self):
927 paths = ssl.get_default_verify_paths()
928 self.assertEqual(len(paths), 6)
929 self.assertIsInstance(paths, ssl.DefaultVerifyPaths)
930
Hai Shia7f5d932020-08-04 00:41:24 +0800931 with os_helper.EnvironmentVarGuard() as env:
Christian Heimes6d7ad132013-06-09 18:02:55 +0200932 env["SSL_CERT_DIR"] = CAPATH
933 env["SSL_CERT_FILE"] = CERTFILE
934 paths = ssl.get_default_verify_paths()
935 self.assertEqual(paths.cafile, CERTFILE)
936 self.assertEqual(paths.capath, CAPATH)
937
Christian Heimes44109d72013-11-22 01:51:30 +0100938 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
939 def test_enum_certificates(self):
940 self.assertTrue(ssl.enum_certificates("CA"))
941 self.assertTrue(ssl.enum_certificates("ROOT"))
942
943 self.assertRaises(TypeError, ssl.enum_certificates)
944 self.assertRaises(WindowsError, ssl.enum_certificates, "")
945
Christian Heimesc2d65e12013-11-22 16:13:55 +0100946 trust_oids = set()
947 for storename in ("CA", "ROOT"):
948 store = ssl.enum_certificates(storename)
949 self.assertIsInstance(store, list)
950 for element in store:
951 self.assertIsInstance(element, tuple)
952 self.assertEqual(len(element), 3)
953 cert, enc, trust = element
954 self.assertIsInstance(cert, bytes)
955 self.assertIn(enc, {"x509_asn", "pkcs_7_asn"})
Christian Heimes915cd3f2019-09-09 18:06:55 +0200956 self.assertIsInstance(trust, (frozenset, set, bool))
957 if isinstance(trust, (frozenset, set)):
Christian Heimesc2d65e12013-11-22 16:13:55 +0100958 trust_oids.update(trust)
Christian Heimes44109d72013-11-22 01:51:30 +0100959
960 serverAuth = "1.3.6.1.5.5.7.3.1"
Christian Heimesc2d65e12013-11-22 16:13:55 +0100961 self.assertIn(serverAuth, trust_oids)
Christian Heimes6d7ad132013-06-09 18:02:55 +0200962
Christian Heimes46bebee2013-06-09 19:03:31 +0200963 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
Christian Heimes44109d72013-11-22 01:51:30 +0100964 def test_enum_crls(self):
965 self.assertTrue(ssl.enum_crls("CA"))
966 self.assertRaises(TypeError, ssl.enum_crls)
967 self.assertRaises(WindowsError, ssl.enum_crls, "")
Christian Heimes46bebee2013-06-09 19:03:31 +0200968
Christian Heimes44109d72013-11-22 01:51:30 +0100969 crls = ssl.enum_crls("CA")
970 self.assertIsInstance(crls, list)
971 for element in crls:
972 self.assertIsInstance(element, tuple)
973 self.assertEqual(len(element), 2)
974 self.assertIsInstance(element[0], bytes)
975 self.assertIn(element[1], {"x509_asn", "pkcs_7_asn"})
Christian Heimes46bebee2013-06-09 19:03:31 +0200976
Christian Heimes46bebee2013-06-09 19:03:31 +0200977
Christian Heimesa6bc95a2013-11-17 19:59:14 +0100978 def test_asn1object(self):
979 expected = (129, 'serverAuth', 'TLS Web Server Authentication',
980 '1.3.6.1.5.5.7.3.1')
981
982 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1')
983 self.assertEqual(val, expected)
984 self.assertEqual(val.nid, 129)
985 self.assertEqual(val.shortname, 'serverAuth')
986 self.assertEqual(val.longname, 'TLS Web Server Authentication')
987 self.assertEqual(val.oid, '1.3.6.1.5.5.7.3.1')
988 self.assertIsInstance(val, ssl._ASN1Object)
989 self.assertRaises(ValueError, ssl._ASN1Object, 'serverAuth')
990
991 val = ssl._ASN1Object.fromnid(129)
992 self.assertEqual(val, expected)
993 self.assertIsInstance(val, ssl._ASN1Object)
994 self.assertRaises(ValueError, ssl._ASN1Object.fromnid, -1)
Christian Heimes5398e1a2013-11-22 16:20:53 +0100995 with self.assertRaisesRegex(ValueError, "unknown NID 100000"):
996 ssl._ASN1Object.fromnid(100000)
Christian Heimesa6bc95a2013-11-17 19:59:14 +0100997 for i in range(1000):
998 try:
999 obj = ssl._ASN1Object.fromnid(i)
1000 except ValueError:
1001 pass
1002 else:
1003 self.assertIsInstance(obj.nid, int)
1004 self.assertIsInstance(obj.shortname, str)
1005 self.assertIsInstance(obj.longname, str)
1006 self.assertIsInstance(obj.oid, (str, type(None)))
1007
1008 val = ssl._ASN1Object.fromname('TLS Web Server Authentication')
1009 self.assertEqual(val, expected)
1010 self.assertIsInstance(val, ssl._ASN1Object)
1011 self.assertEqual(ssl._ASN1Object.fromname('serverAuth'), expected)
1012 self.assertEqual(ssl._ASN1Object.fromname('1.3.6.1.5.5.7.3.1'),
1013 expected)
Christian Heimes5398e1a2013-11-22 16:20:53 +01001014 with self.assertRaisesRegex(ValueError, "unknown object 'serverauth'"):
1015 ssl._ASN1Object.fromname('serverauth')
Christian Heimesa6bc95a2013-11-17 19:59:14 +01001016
Christian Heimes72d28502013-11-23 13:56:58 +01001017 def test_purpose_enum(self):
1018 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1')
1019 self.assertIsInstance(ssl.Purpose.SERVER_AUTH, ssl._ASN1Object)
1020 self.assertEqual(ssl.Purpose.SERVER_AUTH, val)
1021 self.assertEqual(ssl.Purpose.SERVER_AUTH.nid, 129)
1022 self.assertEqual(ssl.Purpose.SERVER_AUTH.shortname, 'serverAuth')
1023 self.assertEqual(ssl.Purpose.SERVER_AUTH.oid,
1024 '1.3.6.1.5.5.7.3.1')
1025
1026 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.2')
1027 self.assertIsInstance(ssl.Purpose.CLIENT_AUTH, ssl._ASN1Object)
1028 self.assertEqual(ssl.Purpose.CLIENT_AUTH, val)
1029 self.assertEqual(ssl.Purpose.CLIENT_AUTH.nid, 130)
1030 self.assertEqual(ssl.Purpose.CLIENT_AUTH.shortname, 'clientAuth')
1031 self.assertEqual(ssl.Purpose.CLIENT_AUTH.oid,
1032 '1.3.6.1.5.5.7.3.2')
1033
Antoine Pitrou3e86ba42013-12-28 17:26:33 +01001034 def test_unsupported_dtls(self):
1035 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
1036 self.addCleanup(s.close)
1037 with self.assertRaises(NotImplementedError) as cx:
Christian Heimesd0486372016-09-10 23:23:33 +02001038 test_wrap_socket(s, cert_reqs=ssl.CERT_NONE)
Antoine Pitrou3e86ba42013-12-28 17:26:33 +01001039 self.assertEqual(str(cx.exception), "only stream sockets are supported")
Christian Heimesa170fa12017-09-15 20:27:30 +02001040 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou3e86ba42013-12-28 17:26:33 +01001041 with self.assertRaises(NotImplementedError) as cx:
1042 ctx.wrap_socket(s)
1043 self.assertEqual(str(cx.exception), "only stream sockets are supported")
1044
Antoine Pitrouc695c952014-04-28 20:57:36 +02001045 def cert_time_ok(self, timestring, timestamp):
1046 self.assertEqual(ssl.cert_time_to_seconds(timestring), timestamp)
1047
1048 def cert_time_fail(self, timestring):
1049 with self.assertRaises(ValueError):
1050 ssl.cert_time_to_seconds(timestring)
1051
1052 @unittest.skipUnless(utc_offset(),
1053 'local time needs to be different from UTC')
1054 def test_cert_time_to_seconds_timezone(self):
1055 # Issue #19940: ssl.cert_time_to_seconds() returns wrong
1056 # results if local timezone is not UTC
1057 self.cert_time_ok("May 9 00:00:00 2007 GMT", 1178668800.0)
1058 self.cert_time_ok("Jan 5 09:34:43 2018 GMT", 1515144883.0)
1059
1060 def test_cert_time_to_seconds(self):
1061 timestring = "Jan 5 09:34:43 2018 GMT"
1062 ts = 1515144883.0
1063 self.cert_time_ok(timestring, ts)
1064 # accept keyword parameter, assert its name
1065 self.assertEqual(ssl.cert_time_to_seconds(cert_time=timestring), ts)
1066 # accept both %e and %d (space or zero generated by strftime)
1067 self.cert_time_ok("Jan 05 09:34:43 2018 GMT", ts)
1068 # case-insensitive
1069 self.cert_time_ok("JaN 5 09:34:43 2018 GmT", ts)
1070 self.cert_time_fail("Jan 5 09:34 2018 GMT") # no seconds
1071 self.cert_time_fail("Jan 5 09:34:43 2018") # no GMT
1072 self.cert_time_fail("Jan 5 09:34:43 2018 UTC") # not GMT timezone
1073 self.cert_time_fail("Jan 35 09:34:43 2018 GMT") # invalid day
1074 self.cert_time_fail("Jon 5 09:34:43 2018 GMT") # invalid month
1075 self.cert_time_fail("Jan 5 24:00:00 2018 GMT") # invalid hour
1076 self.cert_time_fail("Jan 5 09:60:43 2018 GMT") # invalid minute
1077
1078 newyear_ts = 1230768000.0
1079 # leap seconds
1080 self.cert_time_ok("Dec 31 23:59:60 2008 GMT", newyear_ts)
1081 # same timestamp
1082 self.cert_time_ok("Jan 1 00:00:00 2009 GMT", newyear_ts)
1083
1084 self.cert_time_ok("Jan 5 09:34:59 2018 GMT", 1515144899)
1085 # allow 60th second (even if it is not a leap second)
1086 self.cert_time_ok("Jan 5 09:34:60 2018 GMT", 1515144900)
1087 # allow 2nd leap second for compatibility with time.strptime()
1088 self.cert_time_ok("Jan 5 09:34:61 2018 GMT", 1515144901)
1089 self.cert_time_fail("Jan 5 09:34:62 2018 GMT") # invalid seconds
1090
Mike53f7a7c2017-12-14 14:04:53 +03001091 # no special treatment for the special value:
Antoine Pitrouc695c952014-04-28 20:57:36 +02001092 # 99991231235959Z (rfc 5280)
1093 self.cert_time_ok("Dec 31 23:59:59 9999 GMT", 253402300799.0)
1094
1095 @support.run_with_locale('LC_ALL', '')
1096 def test_cert_time_to_seconds_locale(self):
1097 # `cert_time_to_seconds()` should be locale independent
1098
1099 def local_february_name():
1100 return time.strftime('%b', (1, 2, 3, 4, 5, 6, 0, 0, 0))
1101
1102 if local_february_name().lower() == 'feb':
1103 self.skipTest("locale-specific month name needs to be "
1104 "different from C locale")
1105
1106 # locale-independent
1107 self.cert_time_ok("Feb 9 00:00:00 2007 GMT", 1170979200.0)
1108 self.cert_time_fail(local_february_name() + " 9 00:00:00 2007 GMT")
1109
Martin Panter3840b2a2016-03-27 01:53:46 +00001110 def test_connect_ex_error(self):
1111 server = socket.socket(socket.AF_INET)
1112 self.addCleanup(server.close)
Serhiy Storchaka16994912020-04-25 10:06:29 +03001113 port = socket_helper.bind_port(server) # Reserve port but don't listen
Christian Heimesd0486372016-09-10 23:23:33 +02001114 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001115 cert_reqs=ssl.CERT_REQUIRED)
1116 self.addCleanup(s.close)
1117 rc = s.connect_ex((HOST, port))
1118 # Issue #19919: Windows machines or VMs hosted on Windows
1119 # machines sometimes return EWOULDBLOCK.
1120 errors = (
1121 errno.ECONNREFUSED, errno.EHOSTUNREACH, errno.ETIMEDOUT,
1122 errno.EWOULDBLOCK,
1123 )
1124 self.assertIn(rc, errors)
1125
Christian Heimes89d15502021-04-19 06:55:30 +02001126 def test_read_write_zero(self):
1127 # empty reads and writes now work, bpo-42854, bpo-31711
1128 client_context, server_context, hostname = testing_context()
1129 server = ThreadedEchoServer(context=server_context)
1130 with server:
1131 with client_context.wrap_socket(socket.socket(),
1132 server_hostname=hostname) as s:
1133 s.connect((HOST, server.port))
1134 self.assertEqual(s.recv(0), b"")
1135 self.assertEqual(s.send(b""), 0)
1136
Christian Heimesa6bc95a2013-11-17 19:59:14 +01001137
Antoine Pitrou152efa22010-05-16 18:19:27 +00001138class ContextTests(unittest.TestCase):
1139
1140 def test_constructor(self):
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01001141 for protocol in PROTOCOLS:
Christian Heimes2875c602021-04-19 07:27:10 +02001142 with warnings_helper.check_warnings():
1143 ctx = ssl.SSLContext(protocol)
1144 self.assertEqual(ctx.protocol, protocol)
1145 with warnings_helper.check_warnings():
1146 ctx = ssl.SSLContext()
Christian Heimes598894f2016-09-05 23:19:05 +02001147 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001148 self.assertRaises(ValueError, ssl.SSLContext, -1)
1149 self.assertRaises(ValueError, ssl.SSLContext, 42)
1150
Antoine Pitrou152efa22010-05-16 18:19:27 +00001151 def test_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001152 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001153 ctx.set_ciphers("ALL")
1154 ctx.set_ciphers("DEFAULT")
Ezio Melottied3a7d22010-12-01 02:32:32 +00001155 with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
Antoine Pitrou30474062010-05-16 23:46:26 +00001156 ctx.set_ciphers("^$:,;?*'dorothyx")
Antoine Pitrou152efa22010-05-16 18:19:27 +00001157
Christian Heimes892d66e2018-01-29 14:10:18 +01001158 @unittest.skipUnless(PY_SSL_DEFAULT_CIPHERS == 1,
1159 "Test applies only to Python default ciphers")
1160 def test_python_ciphers(self):
1161 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1162 ciphers = ctx.get_ciphers()
1163 for suite in ciphers:
1164 name = suite['name']
1165 self.assertNotIn("PSK", name)
1166 self.assertNotIn("SRP", name)
1167 self.assertNotIn("MD5", name)
1168 self.assertNotIn("RC4", name)
1169 self.assertNotIn("3DES", name)
1170
Christian Heimes25bfcd52016-09-06 00:04:45 +02001171 def test_get_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001172 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesea9b2dc2016-09-06 10:45:44 +02001173 ctx.set_ciphers('AESGCM')
Christian Heimes25bfcd52016-09-06 00:04:45 +02001174 names = set(d['name'] for d in ctx.get_ciphers())
Christian Heimes582282b2016-09-06 11:27:25 +02001175 self.assertIn('AES256-GCM-SHA384', names)
1176 self.assertIn('AES128-GCM-SHA256', names)
Christian Heimes25bfcd52016-09-06 00:04:45 +02001177
Antoine Pitroub5218772010-05-21 09:56:06 +00001178 def test_options(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001179 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Benjamin Petersona9dcdab2015-11-11 22:38:41 -08001180 # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value
Christian Heimes598894f2016-09-05 23:19:05 +02001181 default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
Christian Heimes358cfd42016-09-10 22:43:48 +02001182 # SSLContext also enables these by default
1183 default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE |
Christian Heimes05d9fe32018-02-27 08:55:39 +01001184 OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE |
Christian Heimes6f37ebc2021-04-09 17:59:21 +02001185 OP_ENABLE_MIDDLEBOX_COMPAT |
1186 OP_IGNORE_UNEXPECTED_EOF)
Christian Heimes598894f2016-09-05 23:19:05 +02001187 self.assertEqual(default, ctx.options)
Christian Heimes2875c602021-04-19 07:27:10 +02001188 with warnings_helper.check_warnings():
1189 ctx.options |= ssl.OP_NO_TLSv1
Christian Heimes598894f2016-09-05 23:19:05 +02001190 self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options)
Christian Heimes2875c602021-04-19 07:27:10 +02001191 with warnings_helper.check_warnings():
1192 ctx.options = (ctx.options & ~ssl.OP_NO_TLSv1)
Christian Heimes39258d32021-04-17 11:36:35 +02001193 self.assertEqual(default, ctx.options)
1194 ctx.options = 0
1195 # Ubuntu has OP_NO_SSLv3 forced on by default
1196 self.assertEqual(0, ctx.options & ~ssl.OP_NO_SSLv3)
Antoine Pitroub5218772010-05-21 09:56:06 +00001197
Christian Heimesa170fa12017-09-15 20:27:30 +02001198 def test_verify_mode_protocol(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001199 with warnings_helper.check_warnings():
1200 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001201 # Default value
1202 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1203 ctx.verify_mode = ssl.CERT_OPTIONAL
1204 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1205 ctx.verify_mode = ssl.CERT_REQUIRED
1206 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1207 ctx.verify_mode = ssl.CERT_NONE
1208 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1209 with self.assertRaises(TypeError):
1210 ctx.verify_mode = None
1211 with self.assertRaises(ValueError):
1212 ctx.verify_mode = 42
1213
Christian Heimesa170fa12017-09-15 20:27:30 +02001214 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1215 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1216 self.assertFalse(ctx.check_hostname)
1217
1218 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1219 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1220 self.assertTrue(ctx.check_hostname)
1221
Christian Heimes61d478c2018-01-27 15:51:38 +01001222 def test_hostname_checks_common_name(self):
1223 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1224 self.assertTrue(ctx.hostname_checks_common_name)
1225 if ssl.HAS_NEVER_CHECK_COMMON_NAME:
1226 ctx.hostname_checks_common_name = True
1227 self.assertTrue(ctx.hostname_checks_common_name)
1228 ctx.hostname_checks_common_name = False
1229 self.assertFalse(ctx.hostname_checks_common_name)
1230 ctx.hostname_checks_common_name = True
1231 self.assertTrue(ctx.hostname_checks_common_name)
1232 else:
1233 with self.assertRaises(AttributeError):
1234 ctx.hostname_checks_common_name = True
Christian Heimesa170fa12017-09-15 20:27:30 +02001235
Christian Heimes2875c602021-04-19 07:27:10 +02001236 @ignore_deprecation
Christian Heimes698dde12018-02-27 11:54:43 +01001237 def test_min_max_version(self):
1238 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimes34de2d32019-01-18 16:09:30 +01001239 # OpenSSL default is MINIMUM_SUPPORTED, however some vendors like
1240 # Fedora override the setting to TLS 1.0.
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001241 minimum_range = {
1242 # stock OpenSSL
1243 ssl.TLSVersion.MINIMUM_SUPPORTED,
1244 # Fedora 29 uses TLS 1.0 by default
1245 ssl.TLSVersion.TLSv1,
1246 # RHEL 8 uses TLS 1.2 by default
1247 ssl.TLSVersion.TLSv1_2
1248 }
torsava34864d12019-12-02 17:15:42 +01001249 maximum_range = {
1250 # stock OpenSSL
1251 ssl.TLSVersion.MAXIMUM_SUPPORTED,
1252 # Fedora 32 uses TLS 1.3 by default
1253 ssl.TLSVersion.TLSv1_3
1254 }
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001255
Christian Heimes34de2d32019-01-18 16:09:30 +01001256 self.assertIn(
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001257 ctx.minimum_version, minimum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001258 )
torsava34864d12019-12-02 17:15:42 +01001259 self.assertIn(
1260 ctx.maximum_version, maximum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001261 )
1262
1263 ctx.minimum_version = ssl.TLSVersion.TLSv1_1
1264 ctx.maximum_version = ssl.TLSVersion.TLSv1_2
1265 self.assertEqual(
1266 ctx.minimum_version, ssl.TLSVersion.TLSv1_1
1267 )
1268 self.assertEqual(
1269 ctx.maximum_version, ssl.TLSVersion.TLSv1_2
1270 )
1271
1272 ctx.minimum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1273 ctx.maximum_version = ssl.TLSVersion.TLSv1
1274 self.assertEqual(
1275 ctx.minimum_version, ssl.TLSVersion.MINIMUM_SUPPORTED
1276 )
1277 self.assertEqual(
1278 ctx.maximum_version, ssl.TLSVersion.TLSv1
1279 )
1280
1281 ctx.maximum_version = ssl.TLSVersion.MAXIMUM_SUPPORTED
1282 self.assertEqual(
1283 ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED
1284 )
1285
1286 ctx.maximum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1287 self.assertIn(
1288 ctx.maximum_version,
1289 {ssl.TLSVersion.TLSv1, ssl.TLSVersion.SSLv3}
1290 )
1291
1292 ctx.minimum_version = ssl.TLSVersion.MAXIMUM_SUPPORTED
1293 self.assertIn(
1294 ctx.minimum_version,
1295 {ssl.TLSVersion.TLSv1_2, ssl.TLSVersion.TLSv1_3}
1296 )
1297
1298 with self.assertRaises(ValueError):
1299 ctx.minimum_version = 42
1300
1301 ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_1)
1302
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001303 self.assertIn(
1304 ctx.minimum_version, minimum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001305 )
1306 self.assertEqual(
1307 ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED
1308 )
1309 with self.assertRaises(ValueError):
1310 ctx.minimum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1311 with self.assertRaises(ValueError):
1312 ctx.maximum_version = ssl.TLSVersion.TLSv1
1313
1314
matthewhughes9348e836bb2020-07-17 09:59:15 +01001315 @unittest.skipUnless(
1316 hasattr(ssl.SSLContext, 'security_level'),
1317 "requires OpenSSL >= 1.1.0"
1318 )
1319 def test_security_level(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001320 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
matthewhughes9348e836bb2020-07-17 09:59:15 +01001321 # The default security callback allows for levels between 0-5
1322 # with OpenSSL defaulting to 1, however some vendors override the
1323 # default value (e.g. Debian defaults to 2)
1324 security_level_range = {
1325 0,
1326 1, # OpenSSL default
1327 2, # Debian
1328 3,
1329 4,
1330 5,
1331 }
1332 self.assertIn(ctx.security_level, security_level_range)
1333
Christian Heimes22587792013-11-21 23:56:13 +01001334 def test_verify_flags(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001335 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Benjamin Peterson990fcaa2015-03-04 22:49:41 -05001336 # default value
1337 tf = getattr(ssl, "VERIFY_X509_TRUSTED_FIRST", 0)
1338 self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT | tf)
Christian Heimes22587792013-11-21 23:56:13 +01001339 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF
1340 self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_LEAF)
1341 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_CHAIN
1342 self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_CHAIN)
1343 ctx.verify_flags = ssl.VERIFY_DEFAULT
1344 self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT)
Chris Burre0b4aa02021-03-18 09:24:01 +01001345 ctx.verify_flags = ssl.VERIFY_ALLOW_PROXY_CERTS
1346 self.assertEqual(ctx.verify_flags, ssl.VERIFY_ALLOW_PROXY_CERTS)
Christian Heimes22587792013-11-21 23:56:13 +01001347 # supports any value
1348 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT
1349 self.assertEqual(ctx.verify_flags,
1350 ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT)
1351 with self.assertRaises(TypeError):
1352 ctx.verify_flags = None
1353
Antoine Pitrou152efa22010-05-16 18:19:27 +00001354 def test_load_cert_chain(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001355 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001356 # Combined key and cert in a single file
Benjamin Peterson1ea070e2014-11-03 21:05:01 -05001357 ctx.load_cert_chain(CERTFILE, keyfile=None)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001358 ctx.load_cert_chain(CERTFILE, keyfile=CERTFILE)
1359 self.assertRaises(TypeError, ctx.load_cert_chain, keyfile=CERTFILE)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001360 with self.assertRaises(OSError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001361 ctx.load_cert_chain(NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +00001362 self.assertEqual(cm.exception.errno, errno.ENOENT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001363 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001364 ctx.load_cert_chain(BADCERT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001365 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001366 ctx.load_cert_chain(EMPTYCERT)
1367 # Separate key and cert
Christian Heimesa170fa12017-09-15 20:27:30 +02001368 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001369 ctx.load_cert_chain(ONLYCERT, ONLYKEY)
1370 ctx.load_cert_chain(certfile=ONLYCERT, keyfile=ONLYKEY)
1371 ctx.load_cert_chain(certfile=BYTES_ONLYCERT, keyfile=BYTES_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(ONLYCERT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001374 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001375 ctx.load_cert_chain(ONLYKEY)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001376 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001377 ctx.load_cert_chain(certfile=ONLYKEY, keyfile=ONLYCERT)
1378 # Mismatching key and cert
Christian Heimesa170fa12017-09-15 20:27:30 +02001379 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001380 with self.assertRaisesRegex(ssl.SSLError, "key values mismatch"):
Martin Panter3d81d932016-01-14 09:36:00 +00001381 ctx.load_cert_chain(CAFILE_CACERT, ONLYKEY)
Antoine Pitrou4fd1e6a2011-08-25 14:39:44 +02001382 # Password protected key and cert
1383 ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD)
1384 ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD.encode())
1385 ctx.load_cert_chain(CERTFILE_PROTECTED,
1386 password=bytearray(KEY_PASSWORD.encode()))
1387 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD)
1388 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD.encode())
1389 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED,
1390 bytearray(KEY_PASSWORD.encode()))
1391 with self.assertRaisesRegex(TypeError, "should be a string"):
1392 ctx.load_cert_chain(CERTFILE_PROTECTED, password=True)
1393 with self.assertRaises(ssl.SSLError):
1394 ctx.load_cert_chain(CERTFILE_PROTECTED, password="badpass")
1395 with self.assertRaisesRegex(ValueError, "cannot be longer"):
1396 # openssl has a fixed limit on the password buffer.
1397 # PEM_BUFSIZE is generally set to 1kb.
1398 # Return a string larger than this.
1399 ctx.load_cert_chain(CERTFILE_PROTECTED, password=b'a' * 102400)
1400 # Password callback
1401 def getpass_unicode():
1402 return KEY_PASSWORD
1403 def getpass_bytes():
1404 return KEY_PASSWORD.encode()
1405 def getpass_bytearray():
1406 return bytearray(KEY_PASSWORD.encode())
1407 def getpass_badpass():
1408 return "badpass"
1409 def getpass_huge():
1410 return b'a' * (1024 * 1024)
1411 def getpass_bad_type():
1412 return 9
1413 def getpass_exception():
1414 raise Exception('getpass error')
1415 class GetPassCallable:
1416 def __call__(self):
1417 return KEY_PASSWORD
1418 def getpass(self):
1419 return KEY_PASSWORD
1420 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_unicode)
1421 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytes)
1422 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytearray)
1423 ctx.load_cert_chain(CERTFILE_PROTECTED, password=GetPassCallable())
1424 ctx.load_cert_chain(CERTFILE_PROTECTED,
1425 password=GetPassCallable().getpass)
1426 with self.assertRaises(ssl.SSLError):
1427 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_badpass)
1428 with self.assertRaisesRegex(ValueError, "cannot be longer"):
1429 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_huge)
1430 with self.assertRaisesRegex(TypeError, "must return a string"):
1431 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bad_type)
1432 with self.assertRaisesRegex(Exception, "getpass error"):
1433 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_exception)
1434 # Make sure the password function isn't called if it isn't needed
1435 ctx.load_cert_chain(CERTFILE, password=getpass_exception)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001436
1437 def test_load_verify_locations(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001438 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001439 ctx.load_verify_locations(CERTFILE)
1440 ctx.load_verify_locations(cafile=CERTFILE, capath=None)
1441 ctx.load_verify_locations(BYTES_CERTFILE)
1442 ctx.load_verify_locations(cafile=BYTES_CERTFILE, capath=None)
1443 self.assertRaises(TypeError, ctx.load_verify_locations)
Christian Heimesefff7062013-11-21 03:35:02 +01001444 self.assertRaises(TypeError, ctx.load_verify_locations, None, None, None)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001445 with self.assertRaises(OSError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001446 ctx.load_verify_locations(NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +00001447 self.assertEqual(cm.exception.errno, errno.ENOENT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001448 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001449 ctx.load_verify_locations(BADCERT)
1450 ctx.load_verify_locations(CERTFILE, CAPATH)
1451 ctx.load_verify_locations(CERTFILE, capath=BYTES_CAPATH)
1452
Victor Stinner80f75e62011-01-29 11:31:20 +00001453 # Issue #10989: crash if the second argument type is invalid
1454 self.assertRaises(TypeError, ctx.load_verify_locations, None, True)
1455
Christian Heimesefff7062013-11-21 03:35:02 +01001456 def test_load_verify_cadata(self):
1457 # test cadata
1458 with open(CAFILE_CACERT) as f:
1459 cacert_pem = f.read()
1460 cacert_der = ssl.PEM_cert_to_DER_cert(cacert_pem)
1461 with open(CAFILE_NEURONIO) as f:
1462 neuronio_pem = f.read()
1463 neuronio_der = ssl.PEM_cert_to_DER_cert(neuronio_pem)
1464
1465 # test PEM
Christian Heimesa170fa12017-09-15 20:27:30 +02001466 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001467 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 0)
1468 ctx.load_verify_locations(cadata=cacert_pem)
1469 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 1)
1470 ctx.load_verify_locations(cadata=neuronio_pem)
1471 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1472 # cert already in hash table
1473 ctx.load_verify_locations(cadata=neuronio_pem)
1474 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1475
1476 # combined
Christian Heimesa170fa12017-09-15 20:27:30 +02001477 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001478 combined = "\n".join((cacert_pem, neuronio_pem))
1479 ctx.load_verify_locations(cadata=combined)
1480 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1481
1482 # with junk around the certs
Christian Heimesa170fa12017-09-15 20:27:30 +02001483 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001484 combined = ["head", cacert_pem, "other", neuronio_pem, "again",
1485 neuronio_pem, "tail"]
1486 ctx.load_verify_locations(cadata="\n".join(combined))
1487 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1488
1489 # test DER
Christian Heimesa170fa12017-09-15 20:27:30 +02001490 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001491 ctx.load_verify_locations(cadata=cacert_der)
1492 ctx.load_verify_locations(cadata=neuronio_der)
1493 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1494 # cert already in hash table
1495 ctx.load_verify_locations(cadata=cacert_der)
1496 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1497
1498 # combined
Christian Heimesa170fa12017-09-15 20:27:30 +02001499 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001500 combined = b"".join((cacert_der, neuronio_der))
1501 ctx.load_verify_locations(cadata=combined)
1502 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1503
1504 # error cases
Christian Heimesa170fa12017-09-15 20:27:30 +02001505 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001506 self.assertRaises(TypeError, ctx.load_verify_locations, cadata=object)
1507
Christian Heimesb9ad88b2021-04-23 13:51:40 +02001508 with self.assertRaisesRegex(
1509 ssl.SSLError,
1510 "no start line: cadata does not contain a certificate"
1511 ):
Christian Heimesefff7062013-11-21 03:35:02 +01001512 ctx.load_verify_locations(cadata="broken")
Christian Heimesb9ad88b2021-04-23 13:51:40 +02001513 with self.assertRaisesRegex(
1514 ssl.SSLError,
1515 "not enough data: cadata does not contain a certificate"
1516 ):
Christian Heimesefff7062013-11-21 03:35:02 +01001517 ctx.load_verify_locations(cadata=b"broken")
1518
Paul Monsonf3550692019-06-19 13:09:54 -07001519 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001520 def test_load_dh_params(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001521 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001522 ctx.load_dh_params(DHFILE)
1523 if os.name != 'nt':
1524 ctx.load_dh_params(BYTES_DHFILE)
1525 self.assertRaises(TypeError, ctx.load_dh_params)
1526 self.assertRaises(TypeError, ctx.load_dh_params, None)
1527 with self.assertRaises(FileNotFoundError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001528 ctx.load_dh_params(NONEXISTINGCERT)
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001529 self.assertEqual(cm.exception.errno, errno.ENOENT)
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001530 with self.assertRaises(ssl.SSLError) as cm:
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001531 ctx.load_dh_params(CERTFILE)
1532
Antoine Pitroub0182c82010-10-12 20:09:02 +00001533 def test_session_stats(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001534 for proto in {ssl.PROTOCOL_TLS_CLIENT, ssl.PROTOCOL_TLS_SERVER}:
Antoine Pitroub0182c82010-10-12 20:09:02 +00001535 ctx = ssl.SSLContext(proto)
1536 self.assertEqual(ctx.session_stats(), {
1537 'number': 0,
1538 'connect': 0,
1539 'connect_good': 0,
1540 'connect_renegotiate': 0,
1541 'accept': 0,
1542 'accept_good': 0,
1543 'accept_renegotiate': 0,
1544 'hits': 0,
1545 'misses': 0,
1546 'timeouts': 0,
1547 'cache_full': 0,
1548 })
1549
Antoine Pitrou664c2d12010-11-17 20:29:42 +00001550 def test_set_default_verify_paths(self):
1551 # There's not much we can do to test that it acts as expected,
1552 # so just check it doesn't crash or raise an exception.
Christian Heimesa170fa12017-09-15 20:27:30 +02001553 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou664c2d12010-11-17 20:29:42 +00001554 ctx.set_default_verify_paths()
1555
Antoine Pitrou501da612011-12-21 09:27:41 +01001556 @unittest.skipUnless(ssl.HAS_ECDH, "ECDH disabled on this OpenSSL build")
Antoine Pitrou923df6f2011-12-19 17:16:51 +01001557 def test_set_ecdh_curve(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001558 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou923df6f2011-12-19 17:16:51 +01001559 ctx.set_ecdh_curve("prime256v1")
1560 ctx.set_ecdh_curve(b"prime256v1")
1561 self.assertRaises(TypeError, ctx.set_ecdh_curve)
1562 self.assertRaises(TypeError, ctx.set_ecdh_curve, None)
1563 self.assertRaises(ValueError, ctx.set_ecdh_curve, "foo")
1564 self.assertRaises(ValueError, ctx.set_ecdh_curve, b"foo")
1565
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001566 def test_sni_callback(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001567 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001568
1569 # set_servername_callback expects a callable, or None
1570 self.assertRaises(TypeError, ctx.set_servername_callback)
1571 self.assertRaises(TypeError, ctx.set_servername_callback, 4)
1572 self.assertRaises(TypeError, ctx.set_servername_callback, "")
1573 self.assertRaises(TypeError, ctx.set_servername_callback, ctx)
1574
1575 def dummycallback(sock, servername, ctx):
1576 pass
1577 ctx.set_servername_callback(None)
1578 ctx.set_servername_callback(dummycallback)
1579
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001580 def test_sni_callback_refcycle(self):
1581 # Reference cycles through the servername callback are detected
1582 # and cleared.
Christian Heimesa170fa12017-09-15 20:27:30 +02001583 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001584 def dummycallback(sock, servername, ctx, cycle=ctx):
1585 pass
1586 ctx.set_servername_callback(dummycallback)
1587 wr = weakref.ref(ctx)
1588 del ctx, dummycallback
1589 gc.collect()
1590 self.assertIs(wr(), None)
1591
Christian Heimes9a5395a2013-06-17 15:44:12 +02001592 def test_cert_store_stats(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001593 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001594 self.assertEqual(ctx.cert_store_stats(),
1595 {'x509_ca': 0, 'crl': 0, 'x509': 0})
1596 ctx.load_cert_chain(CERTFILE)
1597 self.assertEqual(ctx.cert_store_stats(),
1598 {'x509_ca': 0, 'crl': 0, 'x509': 0})
1599 ctx.load_verify_locations(CERTFILE)
1600 self.assertEqual(ctx.cert_store_stats(),
1601 {'x509_ca': 0, 'crl': 0, 'x509': 1})
Martin Panterb55f8b72016-01-14 12:53:56 +00001602 ctx.load_verify_locations(CAFILE_CACERT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001603 self.assertEqual(ctx.cert_store_stats(),
1604 {'x509_ca': 1, 'crl': 0, 'x509': 2})
1605
1606 def test_get_ca_certs(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001607 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001608 self.assertEqual(ctx.get_ca_certs(), [])
1609 # CERTFILE is not flagged as X509v3 Basic Constraints: CA:TRUE
1610 ctx.load_verify_locations(CERTFILE)
1611 self.assertEqual(ctx.get_ca_certs(), [])
Martin Panterb55f8b72016-01-14 12:53:56 +00001612 # but CAFILE_CACERT is a CA cert
1613 ctx.load_verify_locations(CAFILE_CACERT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001614 self.assertEqual(ctx.get_ca_certs(),
1615 [{'issuer': ((('organizationName', 'Root CA'),),
1616 (('organizationalUnitName', 'http://www.cacert.org'),),
1617 (('commonName', 'CA Cert Signing Authority'),),
1618 (('emailAddress', 'support@cacert.org'),)),
Christian Heimesd37b74f2021-04-19 08:31:29 +02001619 'notAfter': 'Mar 29 12:29:49 2033 GMT',
1620 'notBefore': 'Mar 30 12:29:49 2003 GMT',
Christian Heimes9a5395a2013-06-17 15:44:12 +02001621 'serialNumber': '00',
Christian Heimesbd3a7f92013-11-21 03:40:15 +01001622 'crlDistributionPoints': ('https://www.cacert.org/revoke.crl',),
Christian Heimes9a5395a2013-06-17 15:44:12 +02001623 'subject': ((('organizationName', 'Root CA'),),
1624 (('organizationalUnitName', 'http://www.cacert.org'),),
1625 (('commonName', 'CA Cert Signing Authority'),),
1626 (('emailAddress', 'support@cacert.org'),)),
1627 'version': 3}])
1628
Martin Panterb55f8b72016-01-14 12:53:56 +00001629 with open(CAFILE_CACERT) as f:
Christian Heimes9a5395a2013-06-17 15:44:12 +02001630 pem = f.read()
1631 der = ssl.PEM_cert_to_DER_cert(pem)
1632 self.assertEqual(ctx.get_ca_certs(True), [der])
1633
Christian Heimes72d28502013-11-23 13:56:58 +01001634 def test_load_default_certs(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001635 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001636 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.SERVER_AUTH)
1640 ctx.load_default_certs()
1641
Christian Heimesa170fa12017-09-15 20:27:30 +02001642 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001643 ctx.load_default_certs(ssl.Purpose.CLIENT_AUTH)
1644
Christian Heimesa170fa12017-09-15 20:27:30 +02001645 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001646 self.assertRaises(TypeError, ctx.load_default_certs, None)
1647 self.assertRaises(TypeError, ctx.load_default_certs, 'SERVER_AUTH')
1648
Benjamin Peterson91244e02014-10-03 18:17:15 -04001649 @unittest.skipIf(sys.platform == "win32", "not-Windows specific")
Benjamin Peterson5915b0f2014-10-03 17:27:05 -04001650 def test_load_default_certs_env(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001651 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Hai Shia7f5d932020-08-04 00:41:24 +08001652 with os_helper.EnvironmentVarGuard() as env:
Benjamin Peterson5915b0f2014-10-03 17:27:05 -04001653 env["SSL_CERT_DIR"] = CAPATH
1654 env["SSL_CERT_FILE"] = CERTFILE
1655 ctx.load_default_certs()
1656 self.assertEqual(ctx.cert_store_stats(), {"crl": 0, "x509": 1, "x509_ca": 0})
1657
Benjamin Peterson91244e02014-10-03 18:17:15 -04001658 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
Steve Dower68d663c2017-07-17 11:15:48 +02001659 @unittest.skipIf(hasattr(sys, "gettotalrefcount"), "Debug build does not share environment between CRTs")
Benjamin Peterson91244e02014-10-03 18:17:15 -04001660 def test_load_default_certs_env_windows(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001661 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Benjamin Peterson91244e02014-10-03 18:17:15 -04001662 ctx.load_default_certs()
1663 stats = ctx.cert_store_stats()
1664
Christian Heimesa170fa12017-09-15 20:27:30 +02001665 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Hai Shia7f5d932020-08-04 00:41:24 +08001666 with os_helper.EnvironmentVarGuard() as env:
Benjamin Peterson91244e02014-10-03 18:17:15 -04001667 env["SSL_CERT_DIR"] = CAPATH
1668 env["SSL_CERT_FILE"] = CERTFILE
1669 ctx.load_default_certs()
1670 stats["x509"] += 1
1671 self.assertEqual(ctx.cert_store_stats(), stats)
1672
Christian Heimes358cfd42016-09-10 22:43:48 +02001673 def _assert_context_options(self, ctx):
1674 self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
1675 if OP_NO_COMPRESSION != 0:
1676 self.assertEqual(ctx.options & OP_NO_COMPRESSION,
1677 OP_NO_COMPRESSION)
1678 if OP_SINGLE_DH_USE != 0:
1679 self.assertEqual(ctx.options & OP_SINGLE_DH_USE,
1680 OP_SINGLE_DH_USE)
1681 if OP_SINGLE_ECDH_USE != 0:
1682 self.assertEqual(ctx.options & OP_SINGLE_ECDH_USE,
1683 OP_SINGLE_ECDH_USE)
1684 if OP_CIPHER_SERVER_PREFERENCE != 0:
1685 self.assertEqual(ctx.options & OP_CIPHER_SERVER_PREFERENCE,
1686 OP_CIPHER_SERVER_PREFERENCE)
1687
Christian Heimes4c05b472013-11-23 15:58:30 +01001688 def test_create_default_context(self):
1689 ctx = ssl.create_default_context()
Christian Heimes358cfd42016-09-10 22:43:48 +02001690
Christian Heimes2875c602021-04-19 07:27:10 +02001691 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes4c05b472013-11-23 15:58:30 +01001692 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001693 self.assertTrue(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001694 self._assert_context_options(ctx)
1695
Christian Heimes4c05b472013-11-23 15:58:30 +01001696 with open(SIGNING_CA) as f:
1697 cadata = f.read()
1698 ctx = ssl.create_default_context(cafile=SIGNING_CA, capath=CAPATH,
1699 cadata=cadata)
Christian Heimes2875c602021-04-19 07:27:10 +02001700 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes4c05b472013-11-23 15:58:30 +01001701 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes358cfd42016-09-10 22:43:48 +02001702 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001703
1704 ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
Christian Heimes2875c602021-04-19 07:27:10 +02001705 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_SERVER)
Christian Heimes4c05b472013-11-23 15:58:30 +01001706 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001707 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001708
Christian Heimes2875c602021-04-19 07:27:10 +02001709
1710
Christian Heimes67986f92013-11-23 22:43:47 +01001711 def test__create_stdlib_context(self):
1712 ctx = ssl._create_stdlib_context()
Christian Heimes2875c602021-04-19 07:27:10 +02001713 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes67986f92013-11-23 22:43:47 +01001714 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001715 self.assertFalse(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001716 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001717
Christian Heimes2875c602021-04-19 07:27:10 +02001718 with warnings_helper.check_warnings():
1719 ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1)
Christian Heimes67986f92013-11-23 22:43:47 +01001720 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
1721 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001722 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001723
Christian Heimes2875c602021-04-19 07:27:10 +02001724 with warnings_helper.check_warnings():
1725 ctx = ssl._create_stdlib_context(
1726 ssl.PROTOCOL_TLSv1_2,
1727 cert_reqs=ssl.CERT_REQUIRED,
1728 check_hostname=True
1729 )
1730 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1_2)
Christian Heimes67986f92013-11-23 22:43:47 +01001731 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimesa02c69a2013-12-02 20:59:28 +01001732 self.assertTrue(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001733 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001734
1735 ctx = ssl._create_stdlib_context(purpose=ssl.Purpose.CLIENT_AUTH)
Christian Heimes2875c602021-04-19 07:27:10 +02001736 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_SERVER)
Christian Heimes67986f92013-11-23 22:43:47 +01001737 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001738 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001739
Christian Heimes1aa9a752013-12-02 02:41:19 +01001740 def test_check_hostname(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001741 with warnings_helper.check_warnings():
1742 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001743 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001744 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001745
Christian Heimese82c0342017-09-15 20:29:57 +02001746 # Auto set CERT_REQUIRED
1747 ctx.check_hostname = True
1748 self.assertTrue(ctx.check_hostname)
1749 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1750 ctx.check_hostname = False
Christian Heimes1aa9a752013-12-02 02:41:19 +01001751 ctx.verify_mode = ssl.CERT_REQUIRED
1752 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001753 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001754
Christian Heimese82c0342017-09-15 20:29:57 +02001755 # Changing verify_mode does not affect check_hostname
1756 ctx.check_hostname = False
1757 ctx.verify_mode = ssl.CERT_NONE
1758 ctx.check_hostname = False
1759 self.assertFalse(ctx.check_hostname)
1760 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1761 # Auto set
Christian Heimes1aa9a752013-12-02 02:41:19 +01001762 ctx.check_hostname = True
1763 self.assertTrue(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001764 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1765
1766 ctx.check_hostname = False
1767 ctx.verify_mode = ssl.CERT_OPTIONAL
1768 ctx.check_hostname = False
1769 self.assertFalse(ctx.check_hostname)
1770 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1771 # keep CERT_OPTIONAL
1772 ctx.check_hostname = True
1773 self.assertTrue(ctx.check_hostname)
1774 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001775
1776 # Cannot set CERT_NONE with check_hostname enabled
1777 with self.assertRaises(ValueError):
1778 ctx.verify_mode = ssl.CERT_NONE
1779 ctx.check_hostname = False
1780 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001781 ctx.verify_mode = ssl.CERT_NONE
1782 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001783
Christian Heimes5fe668c2016-09-12 00:01:11 +02001784 def test_context_client_server(self):
1785 # PROTOCOL_TLS_CLIENT has sane defaults
1786 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1787 self.assertTrue(ctx.check_hostname)
1788 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1789
1790 # PROTOCOL_TLS_SERVER has different but also sane defaults
1791 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1792 self.assertFalse(ctx.check_hostname)
1793 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1794
Christian Heimes4df60f12017-09-15 20:26:05 +02001795 def test_context_custom_class(self):
1796 class MySSLSocket(ssl.SSLSocket):
1797 pass
1798
1799 class MySSLObject(ssl.SSLObject):
1800 pass
1801
1802 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1803 ctx.sslsocket_class = MySSLSocket
1804 ctx.sslobject_class = MySSLObject
1805
1806 with ctx.wrap_socket(socket.socket(), server_side=True) as sock:
1807 self.assertIsInstance(sock, MySSLSocket)
Miss Islington (bot)d7930fb2021-06-11 00:36:17 -07001808 obj = ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(), server_side=True)
Christian Heimes4df60f12017-09-15 20:26:05 +02001809 self.assertIsInstance(obj, MySSLObject)
1810
Christian Heimes78c7d522019-06-03 21:00:10 +02001811 def test_num_tickest(self):
1812 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1813 self.assertEqual(ctx.num_tickets, 2)
1814 ctx.num_tickets = 1
1815 self.assertEqual(ctx.num_tickets, 1)
1816 ctx.num_tickets = 0
1817 self.assertEqual(ctx.num_tickets, 0)
1818 with self.assertRaises(ValueError):
1819 ctx.num_tickets = -1
1820 with self.assertRaises(TypeError):
1821 ctx.num_tickets = None
1822
1823 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1824 self.assertEqual(ctx.num_tickets, 2)
1825 with self.assertRaises(ValueError):
1826 ctx.num_tickets = 1
1827
Antoine Pitrou152efa22010-05-16 18:19:27 +00001828
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001829class SSLErrorTests(unittest.TestCase):
1830
1831 def test_str(self):
1832 # The str() of a SSLError doesn't include the errno
1833 e = ssl.SSLError(1, "foo")
1834 self.assertEqual(str(e), "foo")
1835 self.assertEqual(e.errno, 1)
1836 # Same for a subclass
1837 e = ssl.SSLZeroReturnError(1, "foo")
1838 self.assertEqual(str(e), "foo")
1839 self.assertEqual(e.errno, 1)
1840
Paul Monsonf3550692019-06-19 13:09:54 -07001841 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001842 def test_lib_reason(self):
1843 # Test the library and reason attributes
Christian Heimesa170fa12017-09-15 20:27:30 +02001844 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001845 with self.assertRaises(ssl.SSLError) as cm:
1846 ctx.load_dh_params(CERTFILE)
1847 self.assertEqual(cm.exception.library, 'PEM')
1848 self.assertEqual(cm.exception.reason, 'NO_START_LINE')
1849 s = str(cm.exception)
1850 self.assertTrue(s.startswith("[PEM: NO_START_LINE] no start line"), s)
1851
1852 def test_subclass(self):
1853 # Check that the appropriate SSLError subclass is raised
1854 # (this only tests one of them)
Christian Heimesa170fa12017-09-15 20:27:30 +02001855 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1856 ctx.check_hostname = False
1857 ctx.verify_mode = ssl.CERT_NONE
Giampaolo Rodolaeb7e29f2019-04-09 00:34:02 +02001858 with socket.create_server(("127.0.0.1", 0)) as s:
1859 c = socket.create_connection(s.getsockname())
Antoine Pitroue1ceb502013-01-12 21:54:44 +01001860 c.setblocking(False)
1861 with ctx.wrap_socket(c, False, do_handshake_on_connect=False) as c:
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001862 with self.assertRaises(ssl.SSLWantReadError) as cm:
1863 c.do_handshake()
1864 s = str(cm.exception)
1865 self.assertTrue(s.startswith("The operation did not complete (read)"), s)
1866 # For compatibility
1867 self.assertEqual(cm.exception.errno, ssl.SSL_ERROR_WANT_READ)
1868
1869
Christian Heimes61d478c2018-01-27 15:51:38 +01001870 def test_bad_server_hostname(self):
1871 ctx = ssl.create_default_context()
1872 with self.assertRaises(ValueError):
1873 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1874 server_hostname="")
1875 with self.assertRaises(ValueError):
1876 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1877 server_hostname=".example.org")
Christian Heimesd02ac252018-03-25 12:36:13 +02001878 with self.assertRaises(TypeError):
1879 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1880 server_hostname="example.org\x00evil.com")
Christian Heimes61d478c2018-01-27 15:51:38 +01001881
1882
Antoine Pitroub1fdf472014-10-05 20:41:53 +02001883class MemoryBIOTests(unittest.TestCase):
1884
1885 def test_read_write(self):
1886 bio = ssl.MemoryBIO()
1887 bio.write(b'foo')
1888 self.assertEqual(bio.read(), b'foo')
1889 self.assertEqual(bio.read(), b'')
1890 bio.write(b'foo')
1891 bio.write(b'bar')
1892 self.assertEqual(bio.read(), b'foobar')
1893 self.assertEqual(bio.read(), b'')
1894 bio.write(b'baz')
1895 self.assertEqual(bio.read(2), b'ba')
1896 self.assertEqual(bio.read(1), b'z')
1897 self.assertEqual(bio.read(1), b'')
1898
1899 def test_eof(self):
1900 bio = ssl.MemoryBIO()
1901 self.assertFalse(bio.eof)
1902 self.assertEqual(bio.read(), b'')
1903 self.assertFalse(bio.eof)
1904 bio.write(b'foo')
1905 self.assertFalse(bio.eof)
1906 bio.write_eof()
1907 self.assertFalse(bio.eof)
1908 self.assertEqual(bio.read(2), b'fo')
1909 self.assertFalse(bio.eof)
1910 self.assertEqual(bio.read(1), b'o')
1911 self.assertTrue(bio.eof)
1912 self.assertEqual(bio.read(), b'')
1913 self.assertTrue(bio.eof)
1914
1915 def test_pending(self):
1916 bio = ssl.MemoryBIO()
1917 self.assertEqual(bio.pending, 0)
1918 bio.write(b'foo')
1919 self.assertEqual(bio.pending, 3)
1920 for i in range(3):
1921 bio.read(1)
1922 self.assertEqual(bio.pending, 3-i-1)
1923 for i in range(3):
1924 bio.write(b'x')
1925 self.assertEqual(bio.pending, i+1)
1926 bio.read()
1927 self.assertEqual(bio.pending, 0)
1928
1929 def test_buffer_types(self):
1930 bio = ssl.MemoryBIO()
1931 bio.write(b'foo')
1932 self.assertEqual(bio.read(), b'foo')
1933 bio.write(bytearray(b'bar'))
1934 self.assertEqual(bio.read(), b'bar')
1935 bio.write(memoryview(b'baz'))
1936 self.assertEqual(bio.read(), b'baz')
1937
1938 def test_error_types(self):
1939 bio = ssl.MemoryBIO()
1940 self.assertRaises(TypeError, bio.write, 'foo')
1941 self.assertRaises(TypeError, bio.write, None)
1942 self.assertRaises(TypeError, bio.write, True)
1943 self.assertRaises(TypeError, bio.write, 1)
1944
1945
Christian Heimes9d50ab52018-02-27 10:17:30 +01001946class SSLObjectTests(unittest.TestCase):
1947 def test_private_init(self):
1948 bio = ssl.MemoryBIO()
1949 with self.assertRaisesRegex(TypeError, "public constructor"):
1950 ssl.SSLObject(bio, bio)
1951
Nathaniel J. Smithc0da5822018-09-21 21:44:12 -07001952 def test_unwrap(self):
1953 client_ctx, server_ctx, hostname = testing_context()
1954 c_in = ssl.MemoryBIO()
1955 c_out = ssl.MemoryBIO()
1956 s_in = ssl.MemoryBIO()
1957 s_out = ssl.MemoryBIO()
1958 client = client_ctx.wrap_bio(c_in, c_out, server_hostname=hostname)
1959 server = server_ctx.wrap_bio(s_in, s_out, server_side=True)
1960
1961 # Loop on the handshake for a bit to get it settled
1962 for _ in range(5):
1963 try:
1964 client.do_handshake()
1965 except ssl.SSLWantReadError:
1966 pass
1967 if c_out.pending:
1968 s_in.write(c_out.read())
1969 try:
1970 server.do_handshake()
1971 except ssl.SSLWantReadError:
1972 pass
1973 if s_out.pending:
1974 c_in.write(s_out.read())
1975 # Now the handshakes should be complete (don't raise WantReadError)
1976 client.do_handshake()
1977 server.do_handshake()
1978
1979 # Now if we unwrap one side unilaterally, it should send close-notify
1980 # and raise WantReadError:
1981 with self.assertRaises(ssl.SSLWantReadError):
1982 client.unwrap()
1983
1984 # But server.unwrap() does not raise, because it reads the client's
1985 # close-notify:
1986 s_in.write(c_out.read())
1987 server.unwrap()
1988
1989 # And now that the client gets the server's close-notify, it doesn't
1990 # raise either.
1991 c_in.write(s_out.read())
1992 client.unwrap()
Christian Heimes9d50ab52018-02-27 10:17:30 +01001993
Martin Panter3840b2a2016-03-27 01:53:46 +00001994class SimpleBackgroundTests(unittest.TestCase):
Martin Panter3840b2a2016-03-27 01:53:46 +00001995 """Tests that connect to a simple server running in the background"""
1996
1997 def setUp(self):
juhovh49fdf112021-04-18 21:11:48 +10001998 self.server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1999 self.server_context.load_cert_chain(SIGNED_CERTFILE)
2000 server = ThreadedEchoServer(context=self.server_context)
Martin Panter3840b2a2016-03-27 01:53:46 +00002001 self.server_addr = (HOST, server.port)
2002 server.__enter__()
2003 self.addCleanup(server.__exit__, None, None, None)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002004
Antoine Pitrou480a1242010-04-28 21:37:09 +00002005 def test_connect(self):
Christian Heimesd0486372016-09-10 23:23:33 +02002006 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002007 cert_reqs=ssl.CERT_NONE) as s:
2008 s.connect(self.server_addr)
2009 self.assertEqual({}, s.getpeercert())
Christian Heimesa5d07652016-09-24 10:48:05 +02002010 self.assertFalse(s.server_side)
Antoine Pitrou350c7222010-09-09 13:31:46 +00002011
Martin Panter3840b2a2016-03-27 01:53:46 +00002012 # this should succeed because we specify the root cert
Christian Heimesd0486372016-09-10 23:23:33 +02002013 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002014 cert_reqs=ssl.CERT_REQUIRED,
2015 ca_certs=SIGNING_CA) as s:
2016 s.connect(self.server_addr)
2017 self.assertTrue(s.getpeercert())
Christian Heimesa5d07652016-09-24 10:48:05 +02002018 self.assertFalse(s.server_side)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002019
Martin Panter3840b2a2016-03-27 01:53:46 +00002020 def test_connect_fail(self):
2021 # This should fail because we have no verification certs. Connection
2022 # failure crashes ThreadedEchoServer, so run this in an independent
2023 # test method.
Christian Heimesd0486372016-09-10 23:23:33 +02002024 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002025 cert_reqs=ssl.CERT_REQUIRED)
2026 self.addCleanup(s.close)
2027 self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
2028 s.connect, self.server_addr)
Antoine Pitrou152efa22010-05-16 18:19:27 +00002029
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002030 def test_connect_ex(self):
2031 # Issue #11326: check connect_ex() implementation
Christian Heimesd0486372016-09-10 23:23:33 +02002032 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002033 cert_reqs=ssl.CERT_REQUIRED,
2034 ca_certs=SIGNING_CA)
2035 self.addCleanup(s.close)
2036 self.assertEqual(0, s.connect_ex(self.server_addr))
2037 self.assertTrue(s.getpeercert())
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002038
2039 def test_non_blocking_connect_ex(self):
2040 # Issue #11326: non-blocking connect_ex() should allow handshake
2041 # to proceed after the socket gets ready.
Christian Heimesd0486372016-09-10 23:23:33 +02002042 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002043 cert_reqs=ssl.CERT_REQUIRED,
2044 ca_certs=SIGNING_CA,
2045 do_handshake_on_connect=False)
2046 self.addCleanup(s.close)
2047 s.setblocking(False)
2048 rc = s.connect_ex(self.server_addr)
2049 # EWOULDBLOCK under Windows, EINPROGRESS elsewhere
2050 self.assertIn(rc, (0, errno.EINPROGRESS, errno.EWOULDBLOCK))
2051 # Wait for connect to finish
2052 select.select([], [s], [], 5.0)
2053 # Non-blocking handshake
2054 while True:
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002055 try:
Martin Panter3840b2a2016-03-27 01:53:46 +00002056 s.do_handshake()
2057 break
2058 except ssl.SSLWantReadError:
2059 select.select([s], [], [], 5.0)
2060 except ssl.SSLWantWriteError:
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002061 select.select([], [s], [], 5.0)
Martin Panter3840b2a2016-03-27 01:53:46 +00002062 # SSL established
2063 self.assertTrue(s.getpeercert())
Antoine Pitrou40f12ab2012-12-28 19:03:43 +01002064
Antoine Pitrou152efa22010-05-16 18:19:27 +00002065 def test_connect_with_context(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002066 # Same as test_connect, but with a separately created context
Christian Heimes2875c602021-04-19 07:27:10 +02002067 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2068 ctx.check_hostname = False
2069 ctx.verify_mode = ssl.CERT_NONE
Martin Panter3840b2a2016-03-27 01:53:46 +00002070 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2071 s.connect(self.server_addr)
2072 self.assertEqual({}, s.getpeercert())
2073 # Same with a server hostname
2074 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2075 server_hostname="dummy") as s:
2076 s.connect(self.server_addr)
2077 ctx.verify_mode = ssl.CERT_REQUIRED
2078 # This should succeed because we specify the root cert
2079 ctx.load_verify_locations(SIGNING_CA)
2080 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2081 s.connect(self.server_addr)
2082 cert = s.getpeercert()
2083 self.assertTrue(cert)
2084
2085 def test_connect_with_context_fail(self):
2086 # This should fail because we have no verification certs. Connection
2087 # failure crashes ThreadedEchoServer, so run this in an independent
2088 # test method.
Christian Heimes2875c602021-04-19 07:27:10 +02002089 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2090 s = ctx.wrap_socket(
2091 socket.socket(socket.AF_INET),
2092 server_hostname=SIGNED_CERTFILE_HOSTNAME
2093 )
Martin Panter3840b2a2016-03-27 01:53:46 +00002094 self.addCleanup(s.close)
2095 self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
2096 s.connect, self.server_addr)
Antoine Pitrou152efa22010-05-16 18:19:27 +00002097
2098 def test_connect_capath(self):
2099 # Verify server certificates using the `capath` argument
Antoine Pitrou467f28d2010-05-16 19:22:44 +00002100 # NOTE: the subject hashing algorithm has been changed between
2101 # OpenSSL 0.9.8n and 1.0.0, as a result the capath directory must
2102 # contain both versions of each certificate (same content, different
Antoine Pitroud7e4c1c2010-05-17 14:13:10 +00002103 # filename) for this test to be portable across OpenSSL releases.
Christian Heimes2875c602021-04-19 07:27:10 +02002104 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002105 ctx.load_verify_locations(capath=CAPATH)
Christian Heimes2875c602021-04-19 07:27:10 +02002106 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2107 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002108 s.connect(self.server_addr)
2109 cert = s.getpeercert()
2110 self.assertTrue(cert)
Christian Heimes529525f2018-05-23 22:24:45 +02002111
Martin Panter3840b2a2016-03-27 01:53:46 +00002112 # Same with a bytes `capath` argument
Christian Heimes2875c602021-04-19 07:27:10 +02002113 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002114 ctx.load_verify_locations(capath=BYTES_CAPATH)
Christian Heimes2875c602021-04-19 07:27:10 +02002115 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2116 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002117 s.connect(self.server_addr)
2118 cert = s.getpeercert()
2119 self.assertTrue(cert)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002120
Christian Heimesefff7062013-11-21 03:35:02 +01002121 def test_connect_cadata(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002122 with open(SIGNING_CA) as f:
Christian Heimesefff7062013-11-21 03:35:02 +01002123 pem = f.read()
2124 der = ssl.PEM_cert_to_DER_cert(pem)
Christian Heimes2875c602021-04-19 07:27:10 +02002125 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002126 ctx.load_verify_locations(cadata=pem)
Christian Heimes2875c602021-04-19 07:27:10 +02002127 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2128 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002129 s.connect(self.server_addr)
2130 cert = s.getpeercert()
2131 self.assertTrue(cert)
Christian Heimesefff7062013-11-21 03:35:02 +01002132
Martin Panter3840b2a2016-03-27 01:53:46 +00002133 # same with DER
Christian Heimes2875c602021-04-19 07:27:10 +02002134 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002135 ctx.load_verify_locations(cadata=der)
Christian Heimes2875c602021-04-19 07:27:10 +02002136 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2137 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002138 s.connect(self.server_addr)
2139 cert = s.getpeercert()
2140 self.assertTrue(cert)
Christian Heimesefff7062013-11-21 03:35:02 +01002141
Antoine Pitroue3220242010-04-24 11:13:53 +00002142 @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
2143 def test_makefile_close(self):
2144 # Issue #5238: creating a file-like object with makefile() shouldn't
2145 # delay closing the underlying "real socket" (here tested with its
2146 # file descriptor, hence skipping the test under Windows).
Christian Heimesd0486372016-09-10 23:23:33 +02002147 ss = test_wrap_socket(socket.socket(socket.AF_INET))
Martin Panter3840b2a2016-03-27 01:53:46 +00002148 ss.connect(self.server_addr)
2149 fd = ss.fileno()
2150 f = ss.makefile()
2151 f.close()
2152 # The fd is still open
2153 os.read(fd, 0)
2154 # Closing the SSL socket should close the fd too
2155 ss.close()
2156 gc.collect()
2157 with self.assertRaises(OSError) as e:
Antoine Pitroue3220242010-04-24 11:13:53 +00002158 os.read(fd, 0)
Martin Panter3840b2a2016-03-27 01:53:46 +00002159 self.assertEqual(e.exception.errno, errno.EBADF)
Antoine Pitroue3220242010-04-24 11:13:53 +00002160
Antoine Pitrou480a1242010-04-28 21:37:09 +00002161 def test_non_blocking_handshake(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002162 s = socket.socket(socket.AF_INET)
2163 s.connect(self.server_addr)
2164 s.setblocking(False)
Christian Heimesd0486372016-09-10 23:23:33 +02002165 s = test_wrap_socket(s,
Martin Panter3840b2a2016-03-27 01:53:46 +00002166 cert_reqs=ssl.CERT_NONE,
2167 do_handshake_on_connect=False)
2168 self.addCleanup(s.close)
2169 count = 0
2170 while True:
2171 try:
2172 count += 1
2173 s.do_handshake()
2174 break
2175 except ssl.SSLWantReadError:
2176 select.select([s], [], [])
2177 except ssl.SSLWantWriteError:
2178 select.select([], [s], [])
2179 if support.verbose:
2180 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002181
Antoine Pitrou480a1242010-04-28 21:37:09 +00002182 def test_get_server_certificate(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002183 _test_get_server_certificate(self, *self.server_addr, cert=SIGNING_CA)
Antoine Pitrou5aefa662011-04-28 19:24:46 +02002184
juhovh49fdf112021-04-18 21:11:48 +10002185 def test_get_server_certificate_sni(self):
2186 host, port = self.server_addr
2187 server_names = []
2188
2189 # We store servername_cb arguments to make sure they match the host
2190 def servername_cb(ssl_sock, server_name, initial_context):
2191 server_names.append(server_name)
2192 self.server_context.set_servername_callback(servername_cb)
2193
2194 pem = ssl.get_server_certificate((host, port))
2195 if not pem:
2196 self.fail("No server certificate on %s:%s!" % (host, port))
2197
2198 pem = ssl.get_server_certificate((host, port), ca_certs=SIGNING_CA)
2199 if not pem:
2200 self.fail("No server certificate on %s:%s!" % (host, port))
2201 if support.verbose:
2202 sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port, pem))
2203
2204 self.assertEqual(server_names, [host, host])
2205
Martin Panter3840b2a2016-03-27 01:53:46 +00002206 def test_get_server_certificate_fail(self):
2207 # Connection failure crashes ThreadedEchoServer, so run this in an
2208 # independent test method
2209 _test_get_server_certificate_fail(self, *self.server_addr)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002210
Zackery Spytzb2fac1a2021-04-23 22:46:01 -06002211 def test_get_server_certificate_timeout(self):
Christian Heimesf05c2ae2021-04-24 07:54:08 +02002212 def servername_cb(ssl_sock, server_name, initial_context):
2213 time.sleep(0.2)
2214 self.server_context.set_servername_callback(servername_cb)
2215
Zackery Spytzb2fac1a2021-04-23 22:46:01 -06002216 with self.assertRaises(socket.timeout):
2217 ssl.get_server_certificate(self.server_addr, ca_certs=SIGNING_CA,
Christian Heimesf05c2ae2021-04-24 07:54:08 +02002218 timeout=0.1)
Zackery Spytzb2fac1a2021-04-23 22:46:01 -06002219
Antoine Pitrouf4c7bad2010-08-15 23:02:22 +00002220 def test_ciphers(self):
Christian Heimesd0486372016-09-10 23:23:33 +02002221 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002222 cert_reqs=ssl.CERT_NONE, ciphers="ALL") as s:
2223 s.connect(self.server_addr)
Christian Heimesd0486372016-09-10 23:23:33 +02002224 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002225 cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT") as s:
2226 s.connect(self.server_addr)
2227 # Error checking can happen at instantiation or when connecting
2228 with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
2229 with socket.socket(socket.AF_INET) as sock:
Christian Heimesd0486372016-09-10 23:23:33 +02002230 s = test_wrap_socket(sock,
Martin Panter3840b2a2016-03-27 01:53:46 +00002231 cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
2232 s.connect(self.server_addr)
Antoine Pitroufec12ff2010-04-21 19:46:23 +00002233
Christian Heimes9a5395a2013-06-17 15:44:12 +02002234 def test_get_ca_certs_capath(self):
2235 # capath certs are loaded on request
Christian Heimesa170fa12017-09-15 20:27:30 +02002236 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002237 ctx.load_verify_locations(capath=CAPATH)
2238 self.assertEqual(ctx.get_ca_certs(), [])
Christian Heimesa170fa12017-09-15 20:27:30 +02002239 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2240 server_hostname='localhost') as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002241 s.connect(self.server_addr)
2242 cert = s.getpeercert()
2243 self.assertTrue(cert)
2244 self.assertEqual(len(ctx.get_ca_certs()), 1)
Christian Heimes9a5395a2013-06-17 15:44:12 +02002245
Christian Heimes8e7f3942013-12-05 07:41:08 +01002246 def test_context_setget(self):
2247 # Check that the context of a connected socket can be replaced.
Christian Heimesa170fa12017-09-15 20:27:30 +02002248 ctx1 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2249 ctx1.load_verify_locations(capath=CAPATH)
2250 ctx2 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2251 ctx2.load_verify_locations(capath=CAPATH)
Martin Panter3840b2a2016-03-27 01:53:46 +00002252 s = socket.socket(socket.AF_INET)
Christian Heimesa170fa12017-09-15 20:27:30 +02002253 with ctx1.wrap_socket(s, server_hostname='localhost') as ss:
Martin Panter3840b2a2016-03-27 01:53:46 +00002254 ss.connect(self.server_addr)
2255 self.assertIs(ss.context, ctx1)
2256 self.assertIs(ss._sslobj.context, ctx1)
2257 ss.context = ctx2
2258 self.assertIs(ss.context, ctx2)
2259 self.assertIs(ss._sslobj.context, ctx2)
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002260
2261 def ssl_io_loop(self, sock, incoming, outgoing, func, *args, **kwargs):
2262 # A simple IO loop. Call func(*args) depending on the error we get
2263 # (WANT_READ or WANT_WRITE) move data between the socket and the BIOs.
Victor Stinner0d63bac2019-12-11 11:30:03 +01002264 timeout = kwargs.get('timeout', support.SHORT_TIMEOUT)
Victor Stinner50a72af2017-09-11 09:34:24 -07002265 deadline = time.monotonic() + timeout
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002266 count = 0
2267 while True:
Victor Stinner50a72af2017-09-11 09:34:24 -07002268 if time.monotonic() > deadline:
2269 self.fail("timeout")
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002270 errno = None
2271 count += 1
2272 try:
2273 ret = func(*args)
2274 except ssl.SSLError as e:
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002275 if e.errno not in (ssl.SSL_ERROR_WANT_READ,
Martin Panter40b97ec2016-01-14 13:05:46 +00002276 ssl.SSL_ERROR_WANT_WRITE):
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002277 raise
2278 errno = e.errno
2279 # Get any data from the outgoing BIO irrespective of any error, and
2280 # send it to the socket.
2281 buf = outgoing.read()
2282 sock.sendall(buf)
2283 # If there's no error, we're done. For WANT_READ, we need to get
2284 # data from the socket and put it in the incoming BIO.
2285 if errno is None:
2286 break
2287 elif errno == ssl.SSL_ERROR_WANT_READ:
2288 buf = sock.recv(32768)
2289 if buf:
2290 incoming.write(buf)
2291 else:
2292 incoming.write_eof()
2293 if support.verbose:
2294 sys.stdout.write("Needed %d calls to complete %s().\n"
2295 % (count, func.__name__))
2296 return ret
2297
Martin Panter3840b2a2016-03-27 01:53:46 +00002298 def test_bio_handshake(self):
2299 sock = socket.socket(socket.AF_INET)
2300 self.addCleanup(sock.close)
2301 sock.connect(self.server_addr)
2302 incoming = ssl.MemoryBIO()
2303 outgoing = ssl.MemoryBIO()
Christian Heimesa170fa12017-09-15 20:27:30 +02002304 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2305 self.assertTrue(ctx.check_hostname)
2306 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Martin Panter3840b2a2016-03-27 01:53:46 +00002307 ctx.load_verify_locations(SIGNING_CA)
Christian Heimesa170fa12017-09-15 20:27:30 +02002308 sslobj = ctx.wrap_bio(incoming, outgoing, False,
2309 SIGNED_CERTFILE_HOSTNAME)
Martin Panter3840b2a2016-03-27 01:53:46 +00002310 self.assertIs(sslobj._sslobj.owner, sslobj)
2311 self.assertIsNone(sslobj.cipher())
Christian Heimes68771112017-09-05 21:55:40 -07002312 self.assertIsNone(sslobj.version())
Christian Heimes01113fa2016-09-05 23:23:24 +02002313 self.assertIsNotNone(sslobj.shared_ciphers())
Martin Panter3840b2a2016-03-27 01:53:46 +00002314 self.assertRaises(ValueError, sslobj.getpeercert)
2315 if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
2316 self.assertIsNone(sslobj.get_channel_binding('tls-unique'))
2317 self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
2318 self.assertTrue(sslobj.cipher())
Christian Heimes01113fa2016-09-05 23:23:24 +02002319 self.assertIsNotNone(sslobj.shared_ciphers())
Christian Heimes68771112017-09-05 21:55:40 -07002320 self.assertIsNotNone(sslobj.version())
Martin Panter3840b2a2016-03-27 01:53:46 +00002321 self.assertTrue(sslobj.getpeercert())
2322 if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
2323 self.assertTrue(sslobj.get_channel_binding('tls-unique'))
2324 try:
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002325 self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
Martin Panter3840b2a2016-03-27 01:53:46 +00002326 except ssl.SSLSyscallError:
2327 # If the server shuts down the TCP connection without sending a
2328 # secure shutdown message, this is reported as SSL_ERROR_SYSCALL
2329 pass
2330 self.assertRaises(ssl.SSLError, sslobj.write, b'foo')
2331
2332 def test_bio_read_write_data(self):
2333 sock = socket.socket(socket.AF_INET)
2334 self.addCleanup(sock.close)
2335 sock.connect(self.server_addr)
2336 incoming = ssl.MemoryBIO()
2337 outgoing = ssl.MemoryBIO()
Christian Heimes2875c602021-04-19 07:27:10 +02002338 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2339 ctx.check_hostname = False
Martin Panter3840b2a2016-03-27 01:53:46 +00002340 ctx.verify_mode = ssl.CERT_NONE
2341 sslobj = ctx.wrap_bio(incoming, outgoing, False)
2342 self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
2343 req = b'FOO\n'
2344 self.ssl_io_loop(sock, incoming, outgoing, sslobj.write, req)
2345 buf = self.ssl_io_loop(sock, incoming, outgoing, sslobj.read, 1024)
2346 self.assertEqual(buf, b'foo\n')
2347 self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002348
2349
Serhiy Storchakabedce352021-09-19 22:36:03 +03002350@support.requires_resource('network')
Martin Panter3840b2a2016-03-27 01:53:46 +00002351class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002352
Martin Panter3840b2a2016-03-27 01:53:46 +00002353 def test_timeout_connect_ex(self):
2354 # Issue #12065: on a timeout, connect_ex() should return the original
2355 # errno (mimicking the behaviour of non-SSL sockets).
Serhiy Storchakabfb1cf42020-04-29 10:36:20 +03002356 with socket_helper.transient_internet(REMOTE_HOST):
Christian Heimesd0486372016-09-10 23:23:33 +02002357 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002358 cert_reqs=ssl.CERT_REQUIRED,
2359 do_handshake_on_connect=False)
2360 self.addCleanup(s.close)
2361 s.settimeout(0.0000001)
2362 rc = s.connect_ex((REMOTE_HOST, 443))
2363 if rc == 0:
2364 self.skipTest("REMOTE_HOST responded too quickly")
Carl Meyer29c451c2021-03-27 15:52:28 -06002365 elif rc == errno.ENETUNREACH:
2366 self.skipTest("Network unreachable.")
Martin Panter3840b2a2016-03-27 01:53:46 +00002367 self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK))
2368
Serhiy Storchaka16994912020-04-25 10:06:29 +03002369 @unittest.skipUnless(socket_helper.IPV6_ENABLED, 'Needs IPv6')
Martin Panter3840b2a2016-03-27 01:53:46 +00002370 def test_get_server_certificate_ipv6(self):
Serhiy Storchakabfb1cf42020-04-29 10:36:20 +03002371 with socket_helper.transient_internet('ipv6.google.com'):
Martin Panter3840b2a2016-03-27 01:53:46 +00002372 _test_get_server_certificate(self, 'ipv6.google.com', 443)
2373 _test_get_server_certificate_fail(self, 'ipv6.google.com', 443)
2374
Martin Panter3840b2a2016-03-27 01:53:46 +00002375
2376def _test_get_server_certificate(test, host, port, cert=None):
2377 pem = ssl.get_server_certificate((host, port))
2378 if not pem:
2379 test.fail("No server certificate on %s:%s!" % (host, port))
2380
2381 pem = ssl.get_server_certificate((host, port), ca_certs=cert)
2382 if not pem:
2383 test.fail("No server certificate on %s:%s!" % (host, port))
2384 if support.verbose:
2385 sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem))
2386
2387def _test_get_server_certificate_fail(test, host, port):
2388 try:
2389 pem = ssl.get_server_certificate((host, port), ca_certs=CERTFILE)
2390 except ssl.SSLError as x:
2391 #should fail
2392 if support.verbose:
2393 sys.stdout.write("%s\n" % x)
2394 else:
2395 test.fail("Got server certificate %s for %s:%s!" % (pem, host, port))
2396
2397
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002398from test.ssl_servers import make_https_server
Antoine Pitrou803e6d62010-10-13 10:36:15 +00002399
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002400class ThreadedEchoServer(threading.Thread):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002401
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002402 class ConnectionHandler(threading.Thread):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002403
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002404 """A mildly complicated class, because we want it to work both
2405 with and without the SSL wrapper around the socket connection, so
2406 that we can test the STARTTLS functionality."""
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002407
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002408 def __init__(self, server, connsock, addr):
2409 self.server = server
2410 self.running = False
2411 self.sock = connsock
2412 self.addr = addr
Serhiy Storchaka5eca7f32019-09-01 12:12:52 +03002413 self.sock.setblocking(True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002414 self.sslconn = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002415 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +00002416 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002417
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002418 def wrap_conn(self):
2419 try:
2420 self.sslconn = self.server.context.wrap_socket(
2421 self.sock, server_side=True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002422 self.server.selected_alpn_protocols.append(self.sslconn.selected_alpn_protocol())
Paul Monsonfb7e7502019-05-15 15:38:55 -07002423 except (ConnectionResetError, BrokenPipeError, ConnectionAbortedError) as e:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002424 # We treat ConnectionResetError as though it were an
2425 # SSLError - OpenSSL on Ubuntu abruptly closes the
2426 # connection when asked to use an unsupported protocol.
2427 #
Christian Heimes529525f2018-05-23 22:24:45 +02002428 # BrokenPipeError is raised in TLS 1.3 mode, when OpenSSL
2429 # tries to send session tickets after handshake.
2430 # https://github.com/openssl/openssl/issues/6342
Paul Monsonfb7e7502019-05-15 15:38:55 -07002431 #
2432 # ConnectionAbortedError is raised in TLS 1.3 mode, when OpenSSL
2433 # tries to send session tickets after handshake when using WinSock.
Christian Heimes529525f2018-05-23 22:24:45 +02002434 self.server.conn_errors.append(str(e))
2435 if self.server.chatty:
2436 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
2437 self.running = False
2438 self.close()
2439 return False
2440 except (ssl.SSLError, OSError) as e:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002441 # OSError may occur with wrong protocols, e.g. both
2442 # sides use PROTOCOL_TLS_SERVER.
2443 #
2444 # XXX Various errors can have happened here, for example
2445 # a mismatching protocol version, an invalid certificate,
2446 # or a low-level bug. This should be made more discriminating.
2447 #
2448 # bpo-31323: Store the exception as string to prevent
2449 # a reference leak: server -> conn_errors -> exception
2450 # -> traceback -> self (ConnectionHandler) -> server
2451 self.server.conn_errors.append(str(e))
2452 if self.server.chatty:
2453 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Miss Islington (bot)b3fac2922021-06-24 05:27:35 -07002454
2455 # bpo-44229, bpo-43855, bpo-44237, and bpo-33450:
2456 # Ignore spurious EPROTOTYPE returned by write() on macOS.
2457 # See also http://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/
2458 if e.errno != errno.EPROTOTYPE and sys.platform != "darwin":
2459 self.running = False
2460 self.server.stop()
2461 self.close()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002462 return False
2463 else:
2464 self.server.shared_ciphers.append(self.sslconn.shared_ciphers())
2465 if self.server.context.verify_mode == ssl.CERT_REQUIRED:
2466 cert = self.sslconn.getpeercert()
2467 if support.verbose and self.server.chatty:
2468 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
2469 cert_binary = self.sslconn.getpeercert(True)
2470 if support.verbose and self.server.chatty:
Christian Heimesc8666cf2021-04-24 09:17:54 +02002471 if cert_binary is None:
2472 sys.stdout.write(" client did not provide a cert\n")
2473 else:
2474 sys.stdout.write(f" cert binary is {len(cert_binary)}b\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002475 cipher = self.sslconn.cipher()
2476 if support.verbose and self.server.chatty:
2477 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002478 return True
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002479
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002480 def read(self):
2481 if self.sslconn:
2482 return self.sslconn.read()
2483 else:
2484 return self.sock.recv(1024)
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002485
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002486 def write(self, bytes):
2487 if self.sslconn:
2488 return self.sslconn.write(bytes)
2489 else:
2490 return self.sock.send(bytes)
2491
2492 def close(self):
2493 if self.sslconn:
2494 self.sslconn.close()
2495 else:
2496 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002497
Antoine Pitrou480a1242010-04-28 21:37:09 +00002498 def run(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002499 self.running = True
2500 if not self.server.starttls_server:
2501 if not self.wrap_conn():
2502 return
2503 while self.running:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002504 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002505 msg = self.read()
2506 stripped = msg.strip()
2507 if not stripped:
2508 # eof, so quit this handler
2509 self.running = False
2510 try:
2511 self.sock = self.sslconn.unwrap()
2512 except OSError:
2513 # Many tests shut the TCP connection down
2514 # without an SSL shutdown. This causes
2515 # unwrap() to raise OSError with errno=0!
2516 pass
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00002517 else:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002518 self.sslconn = None
2519 self.close()
2520 elif stripped == b'over':
2521 if support.verbose and self.server.connectionchatty:
2522 sys.stdout.write(" server: client closed connection\n")
2523 self.close()
2524 return
2525 elif (self.server.starttls_server and
2526 stripped == b'STARTTLS'):
2527 if support.verbose and self.server.connectionchatty:
2528 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
2529 self.write(b"OK\n")
2530 if not self.wrap_conn():
2531 return
2532 elif (self.server.starttls_server and self.sslconn
2533 and stripped == b'ENDTLS'):
2534 if support.verbose and self.server.connectionchatty:
2535 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
2536 self.write(b"OK\n")
2537 self.sock = self.sslconn.unwrap()
2538 self.sslconn = None
2539 if support.verbose and self.server.connectionchatty:
2540 sys.stdout.write(" server: connection is now unencrypted...\n")
2541 elif stripped == b'CB tls-unique':
2542 if support.verbose and self.server.connectionchatty:
2543 sys.stdout.write(" server: read CB tls-unique from client, sending our CB data...\n")
2544 data = self.sslconn.get_channel_binding("tls-unique")
2545 self.write(repr(data).encode("us-ascii") + b"\n")
Christian Heimes9fb051f2018-09-23 08:32:31 +02002546 elif stripped == b'PHA':
2547 if support.verbose and self.server.connectionchatty:
2548 sys.stdout.write(" server: initiating post handshake auth\n")
2549 try:
2550 self.sslconn.verify_client_post_handshake()
2551 except ssl.SSLError as e:
2552 self.write(repr(e).encode("us-ascii") + b"\n")
2553 else:
2554 self.write(b"OK\n")
2555 elif stripped == b'HASCERT':
2556 if self.sslconn.getpeercert() is not None:
2557 self.write(b'TRUE\n')
2558 else:
2559 self.write(b'FALSE\n')
2560 elif stripped == b'GETCERT':
2561 cert = self.sslconn.getpeercert()
2562 self.write(repr(cert).encode("us-ascii") + b"\n")
Christian Heimes666991f2021-04-26 15:01:40 +02002563 elif stripped == b'VERIFIEDCHAIN':
2564 certs = self.sslconn._sslobj.get_verified_chain()
2565 self.write(len(certs).to_bytes(1, "big") + b"\n")
2566 elif stripped == b'UNVERIFIEDCHAIN':
2567 certs = self.sslconn._sslobj.get_unverified_chain()
2568 self.write(len(certs).to_bytes(1, "big") + b"\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002569 else:
2570 if (support.verbose and
2571 self.server.connectionchatty):
2572 ctype = (self.sslconn and "encrypted") or "unencrypted"
2573 sys.stdout.write(" server: read %r (%s), sending back %r (%s)...\n"
2574 % (msg, ctype, msg.lower(), ctype))
2575 self.write(msg.lower())
Christian Heimesc8666cf2021-04-24 09:17:54 +02002576 except OSError as e:
2577 # handles SSLError and socket errors
Christian Heimes529525f2018-05-23 22:24:45 +02002578 if self.server.chatty and support.verbose:
Christian Heimesc8666cf2021-04-24 09:17:54 +02002579 if isinstance(e, ConnectionError):
2580 # OpenSSL 1.1.1 sometimes raises
2581 # ConnectionResetError when connection is not
2582 # shut down gracefully.
2583 print(
2584 f" Connection reset by peer: {self.addr}"
2585 )
2586 else:
2587 handle_error("Test server failure:\n")
2588 try:
2589 self.write(b"ERROR\n")
2590 except OSError:
2591 pass
Bill Janssen2f5799b2008-06-29 00:08:12 +00002592 self.close()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002593 self.running = False
Christian Heimes529525f2018-05-23 22:24:45 +02002594
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002595 # normally, we'd just stop here, but for the test
2596 # harness, we want to stop the server
2597 self.server.stop()
Bill Janssen54cc54c2007-12-14 22:08:56 +00002598
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002599 def __init__(self, certificate=None, ssl_version=None,
2600 certreqs=None, cacerts=None,
2601 chatty=True, connectionchatty=False, starttls_server=False,
Christian Heimes2875c602021-04-19 07:27:10 +02002602 alpn_protocols=None,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002603 ciphers=None, context=None):
2604 if context:
2605 self.context = context
2606 else:
2607 self.context = ssl.SSLContext(ssl_version
2608 if ssl_version is not None
Christian Heimesa170fa12017-09-15 20:27:30 +02002609 else ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002610 self.context.verify_mode = (certreqs if certreqs is not None
2611 else ssl.CERT_NONE)
2612 if cacerts:
2613 self.context.load_verify_locations(cacerts)
2614 if certificate:
2615 self.context.load_cert_chain(certificate)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002616 if alpn_protocols:
2617 self.context.set_alpn_protocols(alpn_protocols)
2618 if ciphers:
2619 self.context.set_ciphers(ciphers)
2620 self.chatty = chatty
2621 self.connectionchatty = connectionchatty
2622 self.starttls_server = starttls_server
2623 self.sock = socket.socket()
Serhiy Storchaka16994912020-04-25 10:06:29 +03002624 self.port = socket_helper.bind_port(self.sock)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002625 self.flag = None
2626 self.active = False
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002627 self.selected_alpn_protocols = []
2628 self.shared_ciphers = []
2629 self.conn_errors = []
2630 threading.Thread.__init__(self)
2631 self.daemon = True
2632
2633 def __enter__(self):
2634 self.start(threading.Event())
2635 self.flag.wait()
2636 return self
2637
2638 def __exit__(self, *args):
2639 self.stop()
2640 self.join()
2641
2642 def start(self, flag=None):
2643 self.flag = flag
2644 threading.Thread.start(self)
2645
2646 def run(self):
Christian Heimesc715b522021-05-03 17:45:02 +02002647 self.sock.settimeout(1.0)
2648 self.sock.listen(5)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002649 self.active = True
2650 if self.flag:
2651 # signal an event
2652 self.flag.set()
2653 while self.active:
2654 try:
2655 newconn, connaddr = self.sock.accept()
2656 if support.verbose and self.chatty:
2657 sys.stdout.write(' server: new connection from '
2658 + repr(connaddr) + '\n')
2659 handler = self.ConnectionHandler(self, newconn, connaddr)
2660 handler.start()
2661 handler.join()
Christian Heimesc715b522021-05-03 17:45:02 +02002662 except TimeoutError as e:
2663 if support.verbose:
2664 sys.stdout.write(f' connection timeout {e!r}\n')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002665 except KeyboardInterrupt:
2666 self.stop()
Christian Heimes529525f2018-05-23 22:24:45 +02002667 except BaseException as e:
2668 if support.verbose and self.chatty:
2669 sys.stdout.write(
2670 ' connection handling failed: ' + repr(e) + '\n')
2671
Christian Heimesc715b522021-05-03 17:45:02 +02002672 self.close()
2673
2674 def close(self):
2675 if self.sock is not None:
2676 self.sock.close()
2677 self.sock = None
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002678
2679 def stop(self):
2680 self.active = False
2681
2682class AsyncoreEchoServer(threading.Thread):
2683
2684 # this one's based on asyncore.dispatcher
2685
2686 class EchoServer (asyncore.dispatcher):
2687
2688 class ConnectionHandler(asyncore.dispatcher_with_send):
2689
2690 def __init__(self, conn, certfile):
2691 self.socket = test_wrap_socket(conn, server_side=True,
2692 certfile=certfile,
2693 do_handshake_on_connect=False)
2694 asyncore.dispatcher_with_send.__init__(self, self.socket)
2695 self._ssl_accepting = True
2696 self._do_ssl_handshake()
2697
2698 def readable(self):
2699 if isinstance(self.socket, ssl.SSLSocket):
2700 while self.socket.pending() > 0:
2701 self.handle_read_event()
2702 return True
2703
2704 def _do_ssl_handshake(self):
2705 try:
2706 self.socket.do_handshake()
2707 except (ssl.SSLWantReadError, ssl.SSLWantWriteError):
2708 return
2709 except ssl.SSLEOFError:
2710 return self.handle_close()
2711 except ssl.SSLError:
Bill Janssen54cc54c2007-12-14 22:08:56 +00002712 raise
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002713 except OSError as err:
2714 if err.args[0] == errno.ECONNABORTED:
2715 return self.handle_close()
2716 else:
2717 self._ssl_accepting = False
Bill Janssen54cc54c2007-12-14 22:08:56 +00002718
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002719 def handle_read(self):
2720 if self._ssl_accepting:
2721 self._do_ssl_handshake()
2722 else:
2723 data = self.recv(1024)
2724 if support.verbose:
2725 sys.stdout.write(" server: read %s from client\n" % repr(data))
2726 if not data:
2727 self.close()
2728 else:
2729 self.send(data.lower())
Bill Janssen54cc54c2007-12-14 22:08:56 +00002730
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002731 def handle_close(self):
2732 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002733 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002734 sys.stdout.write(" server: closed connection %s\n" % self.socket)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002735
2736 def handle_error(self):
2737 raise
2738
Trent Nelson78520002008-04-10 20:54:35 +00002739 def __init__(self, certfile):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002740 self.certfile = certfile
2741 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Serhiy Storchaka16994912020-04-25 10:06:29 +03002742 self.port = socket_helper.bind_port(sock, '')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002743 asyncore.dispatcher.__init__(self, sock)
2744 self.listen(5)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002745
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002746 def handle_accepted(self, sock_obj, addr):
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002747 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002748 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
2749 self.ConnectionHandler(sock_obj, self.certfile)
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002750
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002751 def handle_error(self):
2752 raise
Bill Janssen54cc54c2007-12-14 22:08:56 +00002753
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002754 def __init__(self, certfile):
2755 self.flag = None
2756 self.active = False
2757 self.server = self.EchoServer(certfile)
2758 self.port = self.server.port
2759 threading.Thread.__init__(self)
2760 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +00002761
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002762 def __str__(self):
2763 return "<%s %s>" % (self.__class__.__name__, self.server)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002764
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002765 def __enter__(self):
2766 self.start(threading.Event())
2767 self.flag.wait()
2768 return self
Thomas Woutersed03b412007-08-28 21:37:11 +00002769
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002770 def __exit__(self, *args):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002771 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002772 sys.stdout.write(" cleanup: stopping server.\n")
2773 self.stop()
2774 if support.verbose:
2775 sys.stdout.write(" cleanup: joining server thread.\n")
2776 self.join()
2777 if support.verbose:
2778 sys.stdout.write(" cleanup: successfully joined.\n")
2779 # make sure that ConnectionHandler is removed from socket_map
2780 asyncore.close_all(ignore_all=True)
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01002781
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002782 def start (self, flag=None):
2783 self.flag = flag
2784 threading.Thread.start(self)
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01002785
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002786 def run(self):
2787 self.active = True
2788 if self.flag:
2789 self.flag.set()
2790 while self.active:
Antoine Pitrou773b5db2010-04-27 08:53:36 +00002791 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002792 asyncore.loop(1)
2793 except:
2794 pass
Trent Nelson6b240cd2008-04-10 20:12:06 +00002795
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002796 def stop(self):
2797 self.active = False
2798 self.server.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002799
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002800def server_params_test(client_context, server_context, indata=b"FOO\n",
2801 chatty=True, connectionchatty=False, sni_name=None,
2802 session=None):
2803 """
2804 Launch a server, connect a client to it and try various reads
2805 and writes.
2806 """
2807 stats = {}
2808 server = ThreadedEchoServer(context=server_context,
2809 chatty=chatty,
2810 connectionchatty=False)
2811 with server:
2812 with client_context.wrap_socket(socket.socket(),
2813 server_hostname=sni_name, session=session) as s:
2814 s.connect((HOST, server.port))
2815 for arg in [indata, bytearray(indata), memoryview(indata)]:
2816 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002817 if support.verbose:
Antoine Pitrou18c913e2010-04-27 10:59:39 +00002818 sys.stdout.write(
Antoine Pitrou480a1242010-04-28 21:37:09 +00002819 " client: sending %r...\n" % indata)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002820 s.write(arg)
Antoine Pitrou18c913e2010-04-27 10:59:39 +00002821 outdata = s.read()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002822 if connectionchatty:
2823 if support.verbose:
2824 sys.stdout.write(" client: read %r\n" % outdata)
Trent Nelson6b240cd2008-04-10 20:12:06 +00002825 if outdata != indata.lower():
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002826 raise AssertionError(
Antoine Pitrou480a1242010-04-28 21:37:09 +00002827 "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
2828 % (outdata[:20], len(outdata),
2829 indata[:20].lower(), len(indata)))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002830 s.write(b"over\n")
2831 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002832 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00002833 sys.stdout.write(" client: closing connection.\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002834 stats.update({
2835 'compression': s.compression(),
2836 'cipher': s.cipher(),
2837 'peercert': s.getpeercert(),
2838 'client_alpn_protocol': s.selected_alpn_protocol(),
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002839 'version': s.version(),
2840 'session_reused': s.session_reused,
2841 'session': s.session,
2842 })
2843 s.close()
2844 stats['server_alpn_protocols'] = server.selected_alpn_protocols
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002845 stats['server_shared_ciphers'] = server.shared_ciphers
2846 return stats
Trent Nelson6b240cd2008-04-10 20:12:06 +00002847
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002848def try_protocol_combo(server_protocol, client_protocol, expect_success,
2849 certsreqs=None, server_options=0, client_options=0):
2850 """
2851 Try to SSL-connect using *client_protocol* to *server_protocol*.
2852 If *expect_success* is true, assert that the connection succeeds,
2853 if it's false, assert that the connection fails.
2854 Also, if *expect_success* is a string, assert that it is the protocol
2855 version actually used by the connection.
2856 """
2857 if certsreqs is None:
2858 certsreqs = ssl.CERT_NONE
2859 certtype = {
2860 ssl.CERT_NONE: "CERT_NONE",
2861 ssl.CERT_OPTIONAL: "CERT_OPTIONAL",
2862 ssl.CERT_REQUIRED: "CERT_REQUIRED",
2863 }[certsreqs]
2864 if support.verbose:
2865 formatstr = (expect_success and " %s->%s %s\n") or " {%s->%s} %s\n"
2866 sys.stdout.write(formatstr %
2867 (ssl.get_protocol_name(client_protocol),
2868 ssl.get_protocol_name(server_protocol),
2869 certtype))
Christian Heimes2875c602021-04-19 07:27:10 +02002870
2871 with warnings_helper.check_warnings():
2872 # ignore Deprecation warnings
2873 client_context = ssl.SSLContext(client_protocol)
2874 client_context.options |= client_options
2875 server_context = ssl.SSLContext(server_protocol)
2876 server_context.options |= server_options
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002877
Victor Stinner3ef63442019-02-19 18:06:03 +01002878 min_version = PROTOCOL_TO_TLS_VERSION.get(client_protocol, None)
2879 if (min_version is not None
Christian Heimes2875c602021-04-19 07:27:10 +02002880 # SSLContext.minimum_version is only available on recent OpenSSL
2881 # (setter added in OpenSSL 1.1.0, getter added in OpenSSL 1.1.1)
2882 and hasattr(server_context, 'minimum_version')
2883 and server_protocol == ssl.PROTOCOL_TLS
2884 and server_context.minimum_version > min_version
2885 ):
Victor Stinner3ef63442019-02-19 18:06:03 +01002886 # If OpenSSL configuration is strict and requires more recent TLS
2887 # version, we have to change the minimum to test old TLS versions.
Christian Heimes2875c602021-04-19 07:27:10 +02002888 with warnings_helper.check_warnings():
2889 server_context.minimum_version = min_version
Victor Stinner3ef63442019-02-19 18:06:03 +01002890
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002891 # NOTE: we must enable "ALL" ciphers on the client, otherwise an
2892 # SSLv23 client will send an SSLv3 hello (rather than SSLv2)
2893 # starting from OpenSSL 1.0.0 (see issue #8322).
Christian Heimesa170fa12017-09-15 20:27:30 +02002894 if client_context.protocol == ssl.PROTOCOL_TLS:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002895 client_context.set_ciphers("ALL")
2896
Christian Heimesf6c6b582021-03-18 23:06:50 +01002897 seclevel_workaround(server_context, client_context)
2898
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002899 for ctx in (client_context, server_context):
2900 ctx.verify_mode = certsreqs
Christian Heimesbd5c7d22018-01-20 15:16:30 +01002901 ctx.load_cert_chain(SIGNED_CERTFILE)
2902 ctx.load_verify_locations(SIGNING_CA)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002903 try:
2904 stats = server_params_test(client_context, server_context,
2905 chatty=False, connectionchatty=False)
2906 # Protocol mismatch can result in either an SSLError, or a
2907 # "Connection reset by peer" error.
2908 except ssl.SSLError:
2909 if expect_success:
2910 raise
2911 except OSError as e:
2912 if expect_success or e.errno != errno.ECONNRESET:
2913 raise
2914 else:
2915 if not expect_success:
2916 raise AssertionError(
2917 "Client protocol %s succeeded with server protocol %s!"
2918 % (ssl.get_protocol_name(client_protocol),
2919 ssl.get_protocol_name(server_protocol)))
2920 elif (expect_success is not True
2921 and expect_success != stats['version']):
2922 raise AssertionError("version mismatch: expected %r, got %r"
2923 % (expect_success, stats['version']))
2924
2925
2926class ThreadedTests(unittest.TestCase):
2927
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002928 def test_echo(self):
2929 """Basic test of an SSL client connecting to a server"""
2930 if support.verbose:
2931 sys.stdout.write("\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002932
Christian Heimesa170fa12017-09-15 20:27:30 +02002933 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002934
2935 with self.subTest(client=ssl.PROTOCOL_TLS_CLIENT, server=ssl.PROTOCOL_TLS_SERVER):
2936 server_params_test(client_context=client_context,
2937 server_context=server_context,
2938 chatty=True, connectionchatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02002939 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002940
2941 client_context.check_hostname = False
2942 with self.subTest(client=ssl.PROTOCOL_TLS_SERVER, server=ssl.PROTOCOL_TLS_CLIENT):
2943 with self.assertRaises(ssl.SSLError) as e:
2944 server_params_test(client_context=server_context,
2945 server_context=client_context,
2946 chatty=True, connectionchatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02002947 sni_name=hostname)
Miss Islington (bot)d7930fb2021-06-11 00:36:17 -07002948 self.assertIn(
2949 'Cannot create a client socket with a PROTOCOL_TLS_SERVER context',
2950 str(e.exception)
2951 )
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002952
2953 with self.subTest(client=ssl.PROTOCOL_TLS_SERVER, server=ssl.PROTOCOL_TLS_SERVER):
2954 with self.assertRaises(ssl.SSLError) as e:
2955 server_params_test(client_context=server_context,
2956 server_context=server_context,
2957 chatty=True, connectionchatty=True)
Miss Islington (bot)d7930fb2021-06-11 00:36:17 -07002958 self.assertIn(
2959 'Cannot create a client socket with a PROTOCOL_TLS_SERVER context',
2960 str(e.exception)
2961 )
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002962
2963 with self.subTest(client=ssl.PROTOCOL_TLS_CLIENT, server=ssl.PROTOCOL_TLS_CLIENT):
2964 with self.assertRaises(ssl.SSLError) as e:
2965 server_params_test(client_context=server_context,
2966 server_context=client_context,
2967 chatty=True, connectionchatty=True)
Miss Islington (bot)d7930fb2021-06-11 00:36:17 -07002968 self.assertIn(
2969 'Cannot create a client socket with a PROTOCOL_TLS_SERVER context',
2970 str(e.exception))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002971
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002972 def test_getpeercert(self):
2973 if support.verbose:
2974 sys.stdout.write("\n")
Christian Heimesa170fa12017-09-15 20:27:30 +02002975
2976 client_context, server_context, hostname = testing_context()
2977 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002978 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002979 with client_context.wrap_socket(socket.socket(),
2980 do_handshake_on_connect=False,
2981 server_hostname=hostname) as s:
2982 s.connect((HOST, server.port))
2983 # getpeercert() raise ValueError while the handshake isn't
2984 # done.
2985 with self.assertRaises(ValueError):
2986 s.getpeercert()
2987 s.do_handshake()
2988 cert = s.getpeercert()
2989 self.assertTrue(cert, "Can't get peer certificate.")
2990 cipher = s.cipher()
2991 if support.verbose:
2992 sys.stdout.write(pprint.pformat(cert) + '\n')
2993 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
2994 if 'subject' not in cert:
2995 self.fail("No subject field in certificate: %s." %
2996 pprint.pformat(cert))
2997 if ((('organizationName', 'Python Software Foundation'),)
2998 not in cert['subject']):
2999 self.fail(
3000 "Missing or invalid 'organizationName' field in certificate subject; "
3001 "should be 'Python Software Foundation'.")
3002 self.assertIn('notBefore', cert)
3003 self.assertIn('notAfter', cert)
3004 before = ssl.cert_time_to_seconds(cert['notBefore'])
3005 after = ssl.cert_time_to_seconds(cert['notAfter'])
3006 self.assertLess(before, after)
Bill Janssen58afe4c2008-09-08 16:45:19 +00003007
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003008 def test_crl_check(self):
3009 if support.verbose:
3010 sys.stdout.write("\n")
3011
Christian Heimesa170fa12017-09-15 20:27:30 +02003012 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003013
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003014 tf = getattr(ssl, "VERIFY_X509_TRUSTED_FIRST", 0)
Christian Heimesa170fa12017-09-15 20:27:30 +02003015 self.assertEqual(client_context.verify_flags, ssl.VERIFY_DEFAULT | tf)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003016
3017 # VERIFY_DEFAULT should pass
3018 server = ThreadedEchoServer(context=server_context, chatty=True)
3019 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02003020 with client_context.wrap_socket(socket.socket(),
3021 server_hostname=hostname) as s:
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01003022 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003023 cert = s.getpeercert()
3024 self.assertTrue(cert, "Can't get peer certificate.")
Bill Janssen58afe4c2008-09-08 16:45:19 +00003025
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003026 # VERIFY_CRL_CHECK_LEAF without a loaded CRL file fails
Christian Heimesa170fa12017-09-15 20:27:30 +02003027 client_context.verify_flags |= ssl.VERIFY_CRL_CHECK_LEAF
Bill Janssen58afe4c2008-09-08 16:45:19 +00003028
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003029 server = ThreadedEchoServer(context=server_context, chatty=True)
3030 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02003031 with client_context.wrap_socket(socket.socket(),
3032 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003033 with self.assertRaisesRegex(ssl.SSLError,
3034 "certificate verify failed"):
3035 s.connect((HOST, server.port))
Bill Janssen58afe4c2008-09-08 16:45:19 +00003036
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003037 # now load a CRL file. The CRL file is signed by the CA.
Christian Heimesa170fa12017-09-15 20:27:30 +02003038 client_context.load_verify_locations(CRLFILE)
Bill Janssen58afe4c2008-09-08 16:45:19 +00003039
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003040 server = ThreadedEchoServer(context=server_context, chatty=True)
3041 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02003042 with client_context.wrap_socket(socket.socket(),
3043 server_hostname=hostname) as s:
Antoine Pitroub4bebda2014-04-29 10:03:28 +02003044 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003045 cert = s.getpeercert()
3046 self.assertTrue(cert, "Can't get peer certificate.")
Antoine Pitroub4bebda2014-04-29 10:03:28 +02003047
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003048 def test_check_hostname(self):
3049 if support.verbose:
3050 sys.stdout.write("\n")
Antoine Pitroub4bebda2014-04-29 10:03:28 +02003051
Christian Heimesa170fa12017-09-15 20:27:30 +02003052 client_context, server_context, hostname = testing_context()
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003053
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003054 # correct hostname should verify
3055 server = ThreadedEchoServer(context=server_context, chatty=True)
3056 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02003057 with client_context.wrap_socket(socket.socket(),
3058 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003059 s.connect((HOST, server.port))
3060 cert = s.getpeercert()
3061 self.assertTrue(cert, "Can't get peer certificate.")
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003062
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003063 # incorrect hostname should raise an exception
3064 server = ThreadedEchoServer(context=server_context, chatty=True)
3065 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02003066 with client_context.wrap_socket(socket.socket(),
3067 server_hostname="invalid") as s:
Christian Heimes61d478c2018-01-27 15:51:38 +01003068 with self.assertRaisesRegex(
3069 ssl.CertificateError,
3070 "Hostname mismatch, certificate is not valid for 'invalid'."):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003071 s.connect((HOST, server.port))
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003072
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003073 # missing server_hostname arg should cause an exception, too
3074 server = ThreadedEchoServer(context=server_context, chatty=True)
3075 with server:
3076 with socket.socket() as s:
3077 with self.assertRaisesRegex(ValueError,
3078 "check_hostname requires server_hostname"):
Christian Heimesa170fa12017-09-15 20:27:30 +02003079 client_context.wrap_socket(s)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003080
Christian Heimesb467d9a2021-04-17 10:07:19 +02003081 @unittest.skipUnless(
3082 ssl.HAS_NEVER_CHECK_COMMON_NAME, "test requires hostname_checks_common_name"
3083 )
3084 def test_hostname_checks_common_name(self):
3085 client_context, server_context, hostname = testing_context()
3086 assert client_context.hostname_checks_common_name
3087 client_context.hostname_checks_common_name = False
3088
3089 # default cert has a SAN
3090 server = ThreadedEchoServer(context=server_context, chatty=True)
3091 with server:
3092 with client_context.wrap_socket(socket.socket(),
3093 server_hostname=hostname) as s:
3094 s.connect((HOST, server.port))
3095
3096 client_context, server_context, hostname = testing_context(NOSANFILE)
3097 client_context.hostname_checks_common_name = False
3098 server = ThreadedEchoServer(context=server_context, chatty=True)
3099 with server:
3100 with client_context.wrap_socket(socket.socket(),
3101 server_hostname=hostname) as s:
3102 with self.assertRaises(ssl.SSLCertVerificationError):
3103 s.connect((HOST, server.port))
3104
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003105 def test_ecc_cert(self):
3106 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3107 client_context.load_verify_locations(SIGNING_CA)
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003108 client_context.set_ciphers('ECDHE:ECDSA:!NULL:!aRSA')
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003109 hostname = SIGNED_CERTFILE_ECC_HOSTNAME
3110
3111 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3112 # load ECC cert
3113 server_context.load_cert_chain(SIGNED_CERTFILE_ECC)
3114
3115 # correct hostname should verify
3116 server = ThreadedEchoServer(context=server_context, chatty=True)
3117 with server:
3118 with client_context.wrap_socket(socket.socket(),
3119 server_hostname=hostname) as s:
3120 s.connect((HOST, server.port))
3121 cert = s.getpeercert()
3122 self.assertTrue(cert, "Can't get peer certificate.")
3123 cipher = s.cipher()[0].split('-')
3124 self.assertTrue(cipher[:2], ('ECDHE', 'ECDSA'))
3125
3126 def test_dual_rsa_ecc(self):
3127 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3128 client_context.load_verify_locations(SIGNING_CA)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003129 # TODO: fix TLSv1.3 once SSLContext can restrict signature
3130 # algorithms.
Miss Islington (bot)4becc562021-06-13 05:07:00 -07003131 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003132 # only ECDSA certs
3133 client_context.set_ciphers('ECDHE:ECDSA:!NULL:!aRSA')
3134 hostname = SIGNED_CERTFILE_ECC_HOSTNAME
3135
3136 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3137 # load ECC and RSA key/cert pairs
3138 server_context.load_cert_chain(SIGNED_CERTFILE_ECC)
3139 server_context.load_cert_chain(SIGNED_CERTFILE)
3140
3141 # correct hostname should verify
3142 server = ThreadedEchoServer(context=server_context, chatty=True)
3143 with server:
3144 with client_context.wrap_socket(socket.socket(),
3145 server_hostname=hostname) as s:
3146 s.connect((HOST, server.port))
3147 cert = s.getpeercert()
3148 self.assertTrue(cert, "Can't get peer certificate.")
3149 cipher = s.cipher()[0].split('-')
3150 self.assertTrue(cipher[:2], ('ECDHE', 'ECDSA'))
3151
Christian Heimes66e57422018-01-29 14:25:13 +01003152 def test_check_hostname_idn(self):
3153 if support.verbose:
3154 sys.stdout.write("\n")
3155
Christian Heimes11a14932018-02-24 02:35:08 +01003156 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimes66e57422018-01-29 14:25:13 +01003157 server_context.load_cert_chain(IDNSANSFILE)
3158
Christian Heimes11a14932018-02-24 02:35:08 +01003159 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes66e57422018-01-29 14:25:13 +01003160 context.verify_mode = ssl.CERT_REQUIRED
3161 context.check_hostname = True
3162 context.load_verify_locations(SIGNING_CA)
3163
3164 # correct hostname should verify, when specified in several
3165 # different ways
3166 idn_hostnames = [
3167 ('könig.idn.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003168 'xn--knig-5qa.idn.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003169 ('xn--knig-5qa.idn.pythontest.net',
3170 'xn--knig-5qa.idn.pythontest.net'),
3171 (b'xn--knig-5qa.idn.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003172 'xn--knig-5qa.idn.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003173
3174 ('königsgäßchen.idna2003.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003175 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003176 ('xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
3177 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
3178 (b'xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003179 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
3180
3181 # ('königsgäßchen.idna2008.pythontest.net',
3182 # 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3183 ('xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
3184 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3185 (b'xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
3186 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3187
Christian Heimes66e57422018-01-29 14:25:13 +01003188 ]
3189 for server_hostname, expected_hostname in idn_hostnames:
3190 server = ThreadedEchoServer(context=server_context, chatty=True)
3191 with server:
3192 with context.wrap_socket(socket.socket(),
3193 server_hostname=server_hostname) as s:
3194 self.assertEqual(s.server_hostname, expected_hostname)
3195 s.connect((HOST, server.port))
3196 cert = s.getpeercert()
3197 self.assertEqual(s.server_hostname, expected_hostname)
3198 self.assertTrue(cert, "Can't get peer certificate.")
3199
Christian Heimes66e57422018-01-29 14:25:13 +01003200 # incorrect hostname should raise an exception
3201 server = ThreadedEchoServer(context=server_context, chatty=True)
3202 with server:
3203 with context.wrap_socket(socket.socket(),
3204 server_hostname="python.example.org") as s:
3205 with self.assertRaises(ssl.CertificateError):
3206 s.connect((HOST, server.port))
3207
Christian Heimes529525f2018-05-23 22:24:45 +02003208 def test_wrong_cert_tls12(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003209 """Connecting when the server rejects the client's certificate
3210
3211 Launch a server with CERT_REQUIRED, and check that trying to
3212 connect to it with a wrong client certificate fails.
3213 """
Christian Heimes05d9fe32018-02-27 08:55:39 +01003214 client_context, server_context, hostname = testing_context()
Christian Heimes88bfd0b2018-08-14 12:54:19 +02003215 # load client cert that is not signed by trusted CA
3216 client_context.load_cert_chain(CERTFILE)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003217 # require TLS client authentication
3218 server_context.verify_mode = ssl.CERT_REQUIRED
Christian Heimes529525f2018-05-23 22:24:45 +02003219 # TLS 1.3 has different handshake
3220 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimes05d9fe32018-02-27 08:55:39 +01003221
3222 server = ThreadedEchoServer(
3223 context=server_context, chatty=True, connectionchatty=True,
3224 )
3225
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003226 with server, \
Christian Heimes05d9fe32018-02-27 08:55:39 +01003227 client_context.wrap_socket(socket.socket(),
3228 server_hostname=hostname) as s:
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003229 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003230 # Expect either an SSL error about the server rejecting
3231 # the connection, or a low-level connection reset (which
3232 # sometimes happens on Windows)
3233 s.connect((HOST, server.port))
3234 except ssl.SSLError as e:
3235 if support.verbose:
3236 sys.stdout.write("\nSSLError is %r\n" % e)
3237 except OSError as e:
3238 if e.errno != errno.ECONNRESET:
3239 raise
3240 if support.verbose:
3241 sys.stdout.write("\nsocket.error is %r\n" % e)
3242 else:
3243 self.fail("Use of invalid cert should have failed!")
3244
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003245 @requires_tls_version('TLSv1_3')
Christian Heimes529525f2018-05-23 22:24:45 +02003246 def test_wrong_cert_tls13(self):
3247 client_context, server_context, hostname = testing_context()
Christian Heimes88bfd0b2018-08-14 12:54:19 +02003248 # load client cert that is not signed by trusted CA
3249 client_context.load_cert_chain(CERTFILE)
Christian Heimes529525f2018-05-23 22:24:45 +02003250 server_context.verify_mode = ssl.CERT_REQUIRED
3251 server_context.minimum_version = ssl.TLSVersion.TLSv1_3
3252 client_context.minimum_version = ssl.TLSVersion.TLSv1_3
3253
3254 server = ThreadedEchoServer(
3255 context=server_context, chatty=True, connectionchatty=True,
3256 )
3257 with server, \
3258 client_context.wrap_socket(socket.socket(),
Miss Islington (bot)d2ab15f2021-06-03 13:15:15 -07003259 server_hostname=hostname,
3260 suppress_ragged_eofs=False) as s:
Christian Heimes529525f2018-05-23 22:24:45 +02003261 # TLS 1.3 perform client cert exchange after handshake
3262 s.connect((HOST, server.port))
3263 try:
3264 s.write(b'data')
Christian Heimese0472392021-04-23 20:03:25 +02003265 s.read(1000)
3266 s.write(b'should have failed already')
3267 s.read(1000)
Christian Heimes529525f2018-05-23 22:24:45 +02003268 except ssl.SSLError as e:
3269 if support.verbose:
3270 sys.stdout.write("\nSSLError is %r\n" % e)
3271 except OSError as e:
3272 if e.errno != errno.ECONNRESET:
3273 raise
3274 if support.verbose:
3275 sys.stdout.write("\nsocket.error is %r\n" % e)
3276 else:
Miss Islington (bot)d2ab15f2021-06-03 13:15:15 -07003277 self.fail("Use of invalid cert should have failed!")
Christian Heimes529525f2018-05-23 22:24:45 +02003278
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003279 def test_rude_shutdown(self):
3280 """A brutal shutdown of an SSL server should raise an OSError
3281 in the client when attempting handshake.
3282 """
3283 listener_ready = threading.Event()
3284 listener_gone = threading.Event()
3285
3286 s = socket.socket()
Serhiy Storchaka16994912020-04-25 10:06:29 +03003287 port = socket_helper.bind_port(s, HOST)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003288
3289 # `listener` runs in a thread. It sits in an accept() until
3290 # the main thread connects. Then it rudely closes the socket,
3291 # and sets Event `listener_gone` to let the main thread know
3292 # the socket is gone.
3293 def listener():
3294 s.listen()
3295 listener_ready.set()
3296 newsock, addr = s.accept()
3297 newsock.close()
3298 s.close()
3299 listener_gone.set()
3300
3301 def connector():
3302 listener_ready.wait()
3303 with socket.socket() as c:
3304 c.connect((HOST, port))
3305 listener_gone.wait()
Antoine Pitrou40f08742010-04-24 22:04:40 +00003306 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003307 ssl_sock = test_wrap_socket(c)
3308 except OSError:
3309 pass
3310 else:
3311 self.fail('connecting to closed SSL socket should have failed')
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003312
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003313 t = threading.Thread(target=listener)
3314 t.start()
3315 try:
3316 connector()
3317 finally:
Antoine Pitrou5c89b4e2012-11-11 01:25:36 +01003318 t.join()
Antoine Pitrou5c89b4e2012-11-11 01:25:36 +01003319
Christian Heimesb3ad0e52017-09-08 12:00:19 -07003320 def test_ssl_cert_verify_error(self):
3321 if support.verbose:
3322 sys.stdout.write("\n")
3323
3324 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3325 server_context.load_cert_chain(SIGNED_CERTFILE)
3326
3327 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3328
3329 server = ThreadedEchoServer(context=server_context, chatty=True)
3330 with server:
3331 with context.wrap_socket(socket.socket(),
Christian Heimesa170fa12017-09-15 20:27:30 +02003332 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Christian Heimesb3ad0e52017-09-08 12:00:19 -07003333 try:
3334 s.connect((HOST, server.port))
3335 except ssl.SSLError as e:
3336 msg = 'unable to get local issuer certificate'
3337 self.assertIsInstance(e, ssl.SSLCertVerificationError)
3338 self.assertEqual(e.verify_code, 20)
3339 self.assertEqual(e.verify_message, msg)
3340 self.assertIn(msg, repr(e))
3341 self.assertIn('certificate verify failed', repr(e))
3342
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003343 @requires_tls_version('SSLv2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003344 def test_protocol_sslv2(self):
3345 """Connecting to an SSLv2 server with various client options"""
3346 if support.verbose:
3347 sys.stdout.write("\n")
3348 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
3349 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
3350 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
Christian Heimesa170fa12017-09-15 20:27:30 +02003351 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003352 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003353 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
3354 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
3355 # SSLv23 client with specific SSL options
Christian Heimesa170fa12017-09-15 20:27:30 +02003356 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003357 client_options=ssl.OP_NO_SSLv3)
Christian Heimesa170fa12017-09-15 20:27:30 +02003358 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003359 client_options=ssl.OP_NO_TLSv1)
Antoine Pitrou242db722013-05-01 20:52:07 +02003360
Christian Heimesa170fa12017-09-15 20:27:30 +02003361 def test_PROTOCOL_TLS(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003362 """Connecting to an SSLv23 server with various client options"""
3363 if support.verbose:
3364 sys.stdout.write("\n")
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003365 if has_tls_version('SSLv2'):
Antoine Pitrou8f85f902012-01-03 22:46:48 +01003366 try:
Christian Heimesa170fa12017-09-15 20:27:30 +02003367 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv2, True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003368 except OSError as x:
3369 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
3370 if support.verbose:
3371 sys.stdout.write(
3372 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
3373 % str(x))
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003374 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003375 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False)
3376 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003377 if has_tls_version('TLSv1'):
3378 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1')
Antoine Pitrou8f85f902012-01-03 22:46:48 +01003379
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003380 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003381 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False, ssl.CERT_OPTIONAL)
3382 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True, ssl.CERT_OPTIONAL)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003383 if has_tls_version('TLSv1'):
3384 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003385
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003386 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003387 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False, ssl.CERT_REQUIRED)
3388 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True, ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003389 if has_tls_version('TLSv1'):
3390 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003391
3392 # Server with specific SSL options
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003393 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003394 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003395 server_options=ssl.OP_NO_SSLv3)
3396 # Will choose TLSv1
Christian Heimesa170fa12017-09-15 20:27:30 +02003397 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003398 server_options=ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003399 if has_tls_version('TLSv1'):
3400 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, False,
3401 server_options=ssl.OP_NO_TLSv1)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003402
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003403 @requires_tls_version('SSLv3')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003404 def test_protocol_sslv3(self):
3405 """Connecting to an SSLv3 server with various client options"""
3406 if support.verbose:
3407 sys.stdout.write("\n")
3408 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3')
3409 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_OPTIONAL)
3410 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003411 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003412 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003413 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003414 client_options=ssl.OP_NO_SSLv3)
3415 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003416
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003417 @requires_tls_version('TLSv1')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003418 def test_protocol_tlsv1(self):
3419 """Connecting to a TLSv1 server with various client options"""
3420 if support.verbose:
3421 sys.stdout.write("\n")
3422 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1')
3423 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL)
3424 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003425 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003426 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003427 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003428 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003429 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003430 client_options=ssl.OP_NO_TLSv1)
3431
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003432 @requires_tls_version('TLSv1_1')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003433 def test_protocol_tlsv1_1(self):
3434 """Connecting to a TLSv1.1 server with various client options.
3435 Testing against older TLS versions."""
3436 if support.verbose:
3437 sys.stdout.write("\n")
3438 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1')
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003439 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003440 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003441 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003442 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003443 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003444 client_options=ssl.OP_NO_TLSv1_1)
3445
Christian Heimesa170fa12017-09-15 20:27:30 +02003446 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1')
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003447 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False)
3448 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003449
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003450 @requires_tls_version('TLSv1_2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003451 def test_protocol_tlsv1_2(self):
3452 """Connecting to a TLSv1.2 server with various client options.
3453 Testing against older TLS versions."""
3454 if support.verbose:
3455 sys.stdout.write("\n")
3456 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2',
3457 server_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,
3458 client_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003459 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003460 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003461 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003462 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003463 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003464 client_options=ssl.OP_NO_TLSv1_2)
3465
Christian Heimesa170fa12017-09-15 20:27:30 +02003466 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003467 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1, False)
3468 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_2, False)
3469 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False)
3470 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False)
3471
3472 def test_starttls(self):
3473 """Switching from clear text to encrypted and back again."""
3474 msgs = (b"msg 1", b"MSG 2", b"STARTTLS", b"MSG 3", b"msg 4", b"ENDTLS", b"msg 5", b"msg 6")
3475
3476 server = ThreadedEchoServer(CERTFILE,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003477 starttls_server=True,
3478 chatty=True,
3479 connectionchatty=True)
3480 wrapped = False
3481 with server:
3482 s = socket.socket()
Serhiy Storchaka5eca7f32019-09-01 12:12:52 +03003483 s.setblocking(True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003484 s.connect((HOST, server.port))
Antoine Pitroud6494802011-07-21 01:11:30 +02003485 if support.verbose:
3486 sys.stdout.write("\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003487 for indata in msgs:
Antoine Pitroud6494802011-07-21 01:11:30 +02003488 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003489 sys.stdout.write(
3490 " client: sending %r...\n" % indata)
3491 if wrapped:
3492 conn.write(indata)
3493 outdata = conn.read()
3494 else:
3495 s.send(indata)
3496 outdata = s.recv(1024)
3497 msg = outdata.strip().lower()
3498 if indata == b"STARTTLS" and msg.startswith(b"ok"):
3499 # STARTTLS ok, switch to secure mode
3500 if support.verbose:
3501 sys.stdout.write(
3502 " client: read %r from server, starting TLS...\n"
3503 % msg)
Christian Heimesa170fa12017-09-15 20:27:30 +02003504 conn = test_wrap_socket(s)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003505 wrapped = True
3506 elif indata == b"ENDTLS" and msg.startswith(b"ok"):
3507 # ENDTLS ok, switch back to clear text
3508 if support.verbose:
3509 sys.stdout.write(
3510 " client: read %r from server, ending TLS...\n"
3511 % msg)
3512 s = conn.unwrap()
3513 wrapped = False
3514 else:
3515 if support.verbose:
3516 sys.stdout.write(
3517 " client: read %r from server\n" % msg)
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003518 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003519 sys.stdout.write(" client: closing connection.\n")
3520 if wrapped:
3521 conn.write(b"over\n")
3522 else:
3523 s.send(b"over\n")
3524 if wrapped:
3525 conn.close()
3526 else:
3527 s.close()
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003528
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003529 def test_socketserver(self):
3530 """Using socketserver to create and manage SSL connections."""
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003531 server = make_https_server(self, certfile=SIGNED_CERTFILE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003532 # try to connect
3533 if support.verbose:
3534 sys.stdout.write('\n')
3535 with open(CERTFILE, 'rb') as f:
3536 d1 = f.read()
3537 d2 = ''
3538 # now fetch the same data from the HTTPS server
3539 url = 'https://localhost:%d/%s' % (
3540 server.port, os.path.split(CERTFILE)[1])
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003541 context = ssl.create_default_context(cafile=SIGNING_CA)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003542 f = urllib.request.urlopen(url, context=context)
3543 try:
3544 dlen = f.info().get("content-length")
3545 if dlen and (int(dlen) > 0):
3546 d2 = f.read(int(dlen))
3547 if support.verbose:
3548 sys.stdout.write(
3549 " client: read %d bytes from remote server '%s'\n"
3550 % (len(d2), server))
3551 finally:
3552 f.close()
3553 self.assertEqual(d1, d2)
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003554
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003555 def test_asyncore_server(self):
3556 """Check the example asyncore integration."""
3557 if support.verbose:
3558 sys.stdout.write("\n")
Antoine Pitrou0e576f12011-12-22 10:03:38 +01003559
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003560 indata = b"FOO\n"
3561 server = AsyncoreEchoServer(CERTFILE)
3562 with server:
3563 s = test_wrap_socket(socket.socket())
3564 s.connect(('127.0.0.1', server.port))
3565 if support.verbose:
3566 sys.stdout.write(
3567 " client: sending %r...\n" % indata)
3568 s.write(indata)
3569 outdata = s.read()
3570 if support.verbose:
3571 sys.stdout.write(" client: read %r\n" % outdata)
3572 if outdata != indata.lower():
3573 self.fail(
3574 "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
3575 % (outdata[:20], len(outdata),
3576 indata[:20].lower(), len(indata)))
3577 s.write(b"over\n")
3578 if support.verbose:
3579 sys.stdout.write(" client: closing connection.\n")
3580 s.close()
3581 if support.verbose:
3582 sys.stdout.write(" client: connection closed.\n")
Benjamin Petersoncca27322015-01-23 16:35:37 -05003583
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003584 def test_recv_send(self):
3585 """Test recv(), send() and friends."""
3586 if support.verbose:
3587 sys.stdout.write("\n")
3588
3589 server = ThreadedEchoServer(CERTFILE,
3590 certreqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003591 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003592 cacerts=CERTFILE,
3593 chatty=True,
3594 connectionchatty=False)
3595 with server:
3596 s = test_wrap_socket(socket.socket(),
3597 server_side=False,
3598 certfile=CERTFILE,
3599 ca_certs=CERTFILE,
Christian Heimes2875c602021-04-19 07:27:10 +02003600 cert_reqs=ssl.CERT_NONE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003601 s.connect((HOST, server.port))
3602 # helper methods for standardising recv* method signatures
3603 def _recv_into():
3604 b = bytearray(b"\0"*100)
3605 count = s.recv_into(b)
3606 return b[:count]
3607
3608 def _recvfrom_into():
3609 b = bytearray(b"\0"*100)
3610 count, addr = s.recvfrom_into(b)
3611 return b[:count]
3612
3613 # (name, method, expect success?, *args, return value func)
3614 send_methods = [
3615 ('send', s.send, True, [], len),
3616 ('sendto', s.sendto, False, ["some.address"], len),
3617 ('sendall', s.sendall, True, [], lambda x: None),
3618 ]
3619 # (name, method, whether to expect success, *args)
3620 recv_methods = [
3621 ('recv', s.recv, True, []),
3622 ('recvfrom', s.recvfrom, False, ["some.address"]),
3623 ('recv_into', _recv_into, True, []),
3624 ('recvfrom_into', _recvfrom_into, False, []),
3625 ]
3626 data_prefix = "PREFIX_"
3627
3628 for (meth_name, send_meth, expect_success, args,
3629 ret_val_meth) in send_methods:
3630 indata = (data_prefix + meth_name).encode('ascii')
3631 try:
3632 ret = send_meth(indata, *args)
3633 msg = "sending with {}".format(meth_name)
3634 self.assertEqual(ret, ret_val_meth(indata), msg=msg)
3635 outdata = s.read()
3636 if outdata != indata.lower():
3637 self.fail(
3638 "While sending with <<{name:s}>> bad data "
3639 "<<{outdata:r}>> ({nout:d}) received; "
3640 "expected <<{indata:r}>> ({nin:d})\n".format(
3641 name=meth_name, outdata=outdata[:20],
3642 nout=len(outdata),
3643 indata=indata[:20], nin=len(indata)
3644 )
3645 )
3646 except ValueError as e:
3647 if expect_success:
3648 self.fail(
3649 "Failed to send with method <<{name:s}>>; "
3650 "expected to succeed.\n".format(name=meth_name)
3651 )
3652 if not str(e).startswith(meth_name):
3653 self.fail(
3654 "Method <<{name:s}>> failed with unexpected "
3655 "exception message: {exp:s}\n".format(
3656 name=meth_name, exp=e
3657 )
3658 )
3659
3660 for meth_name, recv_meth, expect_success, args in recv_methods:
3661 indata = (data_prefix + meth_name).encode('ascii')
3662 try:
3663 s.send(indata)
3664 outdata = recv_meth(*args)
3665 if outdata != indata.lower():
3666 self.fail(
3667 "While receiving with <<{name:s}>> bad data "
3668 "<<{outdata:r}>> ({nout:d}) received; "
3669 "expected <<{indata:r}>> ({nin:d})\n".format(
3670 name=meth_name, outdata=outdata[:20],
3671 nout=len(outdata),
3672 indata=indata[:20], nin=len(indata)
3673 )
3674 )
3675 except ValueError as e:
3676 if expect_success:
3677 self.fail(
3678 "Failed to receive with method <<{name:s}>>; "
3679 "expected to succeed.\n".format(name=meth_name)
3680 )
3681 if not str(e).startswith(meth_name):
3682 self.fail(
3683 "Method <<{name:s}>> failed with unexpected "
3684 "exception message: {exp:s}\n".format(
3685 name=meth_name, exp=e
3686 )
3687 )
3688 # consume data
3689 s.read()
3690
3691 # read(-1, buffer) is supported, even though read(-1) is not
3692 data = b"data"
3693 s.send(data)
3694 buffer = bytearray(len(data))
3695 self.assertEqual(s.read(-1, buffer), len(data))
3696 self.assertEqual(buffer, data)
3697
Christian Heimes888bbdc2017-09-07 14:18:21 -07003698 # sendall accepts bytes-like objects
3699 if ctypes is not None:
3700 ubyte = ctypes.c_ubyte * len(data)
3701 byteslike = ubyte.from_buffer_copy(data)
3702 s.sendall(byteslike)
3703 self.assertEqual(s.read(), data)
3704
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003705 # Make sure sendmsg et al are disallowed to avoid
3706 # inadvertent disclosure of data and/or corruption
3707 # of the encrypted data stream
Serhiy Storchaka42b1d612018-12-06 22:36:55 +02003708 self.assertRaises(NotImplementedError, s.dup)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003709 self.assertRaises(NotImplementedError, s.sendmsg, [b"data"])
3710 self.assertRaises(NotImplementedError, s.recvmsg, 100)
3711 self.assertRaises(NotImplementedError,
Serhiy Storchaka42b1d612018-12-06 22:36:55 +02003712 s.recvmsg_into, [bytearray(100)])
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003713 s.write(b"over\n")
3714
3715 self.assertRaises(ValueError, s.recv, -1)
3716 self.assertRaises(ValueError, s.read, -1)
3717
3718 s.close()
3719
3720 def test_recv_zero(self):
3721 server = ThreadedEchoServer(CERTFILE)
3722 server.__enter__()
3723 self.addCleanup(server.__exit__, None, None)
3724 s = socket.create_connection((HOST, server.port))
3725 self.addCleanup(s.close)
3726 s = test_wrap_socket(s, suppress_ragged_eofs=False)
3727 self.addCleanup(s.close)
3728
3729 # recv/read(0) should return no data
3730 s.send(b"data")
3731 self.assertEqual(s.recv(0), b"")
3732 self.assertEqual(s.read(0), b"")
3733 self.assertEqual(s.read(), b"data")
3734
3735 # Should not block if the other end sends no data
3736 s.setblocking(False)
3737 self.assertEqual(s.recv(0), b"")
3738 self.assertEqual(s.recv_into(bytearray()), 0)
3739
3740 def test_nonblocking_send(self):
3741 server = ThreadedEchoServer(CERTFILE,
3742 certreqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003743 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003744 cacerts=CERTFILE,
3745 chatty=True,
3746 connectionchatty=False)
3747 with server:
3748 s = test_wrap_socket(socket.socket(),
3749 server_side=False,
3750 certfile=CERTFILE,
3751 ca_certs=CERTFILE,
Christian Heimes2875c602021-04-19 07:27:10 +02003752 cert_reqs=ssl.CERT_NONE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003753 s.connect((HOST, server.port))
3754 s.setblocking(False)
3755
3756 # If we keep sending data, at some point the buffers
3757 # will be full and the call will block
3758 buf = bytearray(8192)
3759 def fill_buffer():
3760 while True:
3761 s.send(buf)
3762 self.assertRaises((ssl.SSLWantWriteError,
3763 ssl.SSLWantReadError), fill_buffer)
3764
3765 # Now read all the output and discard it
3766 s.setblocking(True)
3767 s.close()
3768
3769 def test_handshake_timeout(self):
3770 # Issue #5103: SSL handshake must respect the socket timeout
3771 server = socket.socket(socket.AF_INET)
3772 host = "127.0.0.1"
Serhiy Storchaka16994912020-04-25 10:06:29 +03003773 port = socket_helper.bind_port(server)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003774 started = threading.Event()
3775 finish = False
3776
3777 def serve():
3778 server.listen()
3779 started.set()
3780 conns = []
3781 while not finish:
3782 r, w, e = select.select([server], [], [], 0.1)
3783 if server in r:
3784 # Let the socket hang around rather than having
3785 # it closed by garbage collection.
3786 conns.append(server.accept()[0])
3787 for sock in conns:
3788 sock.close()
3789
3790 t = threading.Thread(target=serve)
3791 t.start()
3792 started.wait()
3793
3794 try:
3795 try:
3796 c = socket.socket(socket.AF_INET)
3797 c.settimeout(0.2)
3798 c.connect((host, port))
3799 # Will attempt handshake and time out
Christian Heimes03c8ddd2020-11-20 09:26:07 +01003800 self.assertRaisesRegex(TimeoutError, "timed out",
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003801 test_wrap_socket, c)
3802 finally:
3803 c.close()
3804 try:
3805 c = socket.socket(socket.AF_INET)
3806 c = test_wrap_socket(c)
3807 c.settimeout(0.2)
3808 # Will attempt handshake and time out
Christian Heimes03c8ddd2020-11-20 09:26:07 +01003809 self.assertRaisesRegex(TimeoutError, "timed out",
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003810 c.connect, (host, port))
3811 finally:
3812 c.close()
3813 finally:
3814 finish = True
3815 t.join()
3816 server.close()
3817
3818 def test_server_accept(self):
3819 # Issue #16357: accept() on a SSLSocket created through
3820 # SSLContext.wrap_socket().
Christian Heimes2875c602021-04-19 07:27:10 +02003821 client_ctx, server_ctx, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003822 server = socket.socket(socket.AF_INET)
3823 host = "127.0.0.1"
Serhiy Storchaka16994912020-04-25 10:06:29 +03003824 port = socket_helper.bind_port(server)
Christian Heimes2875c602021-04-19 07:27:10 +02003825 server = server_ctx.wrap_socket(server, server_side=True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003826 self.assertTrue(server.server_side)
3827
3828 evt = threading.Event()
3829 remote = None
3830 peer = None
3831 def serve():
3832 nonlocal remote, peer
3833 server.listen()
3834 # Block on the accept and wait on the connection to close.
3835 evt.set()
3836 remote, peer = server.accept()
Christian Heimes529525f2018-05-23 22:24:45 +02003837 remote.send(remote.recv(4))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003838
3839 t = threading.Thread(target=serve)
3840 t.start()
3841 # Client wait until server setup and perform a connect.
3842 evt.wait()
Christian Heimes2875c602021-04-19 07:27:10 +02003843 client = client_ctx.wrap_socket(
3844 socket.socket(), server_hostname=hostname
3845 )
3846 client.connect((hostname, port))
Christian Heimes529525f2018-05-23 22:24:45 +02003847 client.send(b'data')
3848 client.recv()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003849 client_addr = client.getsockname()
3850 client.close()
3851 t.join()
3852 remote.close()
3853 server.close()
3854 # Sanity checks.
3855 self.assertIsInstance(remote, ssl.SSLSocket)
3856 self.assertEqual(peer, client_addr)
3857
3858 def test_getpeercert_enotconn(self):
Christian Heimes2875c602021-04-19 07:27:10 +02003859 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3860 context.check_hostname = False
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003861 with context.wrap_socket(socket.socket()) as sock:
3862 with self.assertRaises(OSError) as cm:
3863 sock.getpeercert()
3864 self.assertEqual(cm.exception.errno, errno.ENOTCONN)
3865
3866 def test_do_handshake_enotconn(self):
Christian Heimes2875c602021-04-19 07:27:10 +02003867 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3868 context.check_hostname = False
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003869 with context.wrap_socket(socket.socket()) as sock:
3870 with self.assertRaises(OSError) as cm:
3871 sock.do_handshake()
3872 self.assertEqual(cm.exception.errno, errno.ENOTCONN)
3873
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003874 def test_no_shared_ciphers(self):
3875 client_context, server_context, hostname = testing_context()
3876 # OpenSSL enables all TLS 1.3 ciphers, enforce TLS 1.2 for test
Miss Islington (bot)4becc562021-06-13 05:07:00 -07003877 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Victor Stinner5e922652018-09-07 17:30:33 +02003878 # Force different suites on client and server
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003879 client_context.set_ciphers("AES128")
3880 server_context.set_ciphers("AES256")
3881 with ThreadedEchoServer(context=server_context) as server:
3882 with client_context.wrap_socket(socket.socket(),
3883 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003884 with self.assertRaises(OSError):
3885 s.connect((HOST, server.port))
3886 self.assertIn("no shared cipher", server.conn_errors[0])
3887
3888 def test_version_basic(self):
3889 """
3890 Basic tests for SSLSocket.version().
3891 More tests are done in the test_protocol_*() methods.
3892 """
Christian Heimesa170fa12017-09-15 20:27:30 +02003893 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3894 context.check_hostname = False
3895 context.verify_mode = ssl.CERT_NONE
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003896 with ThreadedEchoServer(CERTFILE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003897 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003898 chatty=False) as server:
3899 with context.wrap_socket(socket.socket()) as s:
3900 self.assertIs(s.version(), None)
Christian Heimes141c5e82018-02-24 21:10:57 +01003901 self.assertIs(s._sslobj, None)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003902 s.connect((HOST, server.port))
Christian Heimes39258d32021-04-17 11:36:35 +02003903 self.assertEqual(s.version(), 'TLSv1.3')
Christian Heimes141c5e82018-02-24 21:10:57 +01003904 self.assertIs(s._sslobj, None)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003905 self.assertIs(s.version(), None)
3906
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003907 @requires_tls_version('TLSv1_3')
Christian Heimescb5b68a2017-09-07 18:07:00 -07003908 def test_tls1_3(self):
Christian Heimes2875c602021-04-19 07:27:10 +02003909 client_context, server_context, hostname = testing_context()
3910 client_context.minimum_version = ssl.TLSVersion.TLSv1_3
3911 with ThreadedEchoServer(context=server_context) as server:
3912 with client_context.wrap_socket(socket.socket(),
3913 server_hostname=hostname) as s:
Christian Heimescb5b68a2017-09-07 18:07:00 -07003914 s.connect((HOST, server.port))
Christian Heimes05d9fe32018-02-27 08:55:39 +01003915 self.assertIn(s.cipher()[0], {
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003916 'TLS_AES_256_GCM_SHA384',
3917 'TLS_CHACHA20_POLY1305_SHA256',
3918 'TLS_AES_128_GCM_SHA256',
Christian Heimes05d9fe32018-02-27 08:55:39 +01003919 })
3920 self.assertEqual(s.version(), 'TLSv1.3')
Christian Heimescb5b68a2017-09-07 18:07:00 -07003921
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003922 @requires_tls_version('TLSv1_2')
Christian Heimes2875c602021-04-19 07:27:10 +02003923 @requires_tls_version('TLSv1')
3924 @ignore_deprecation
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003925 def test_min_max_version_tlsv1_2(self):
Christian Heimes698dde12018-02-27 11:54:43 +01003926 client_context, server_context, hostname = testing_context()
3927 # client TLSv1.0 to 1.2
3928 client_context.minimum_version = ssl.TLSVersion.TLSv1
3929 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
3930 # server only TLSv1.2
3931 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
3932 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
3933
3934 with ThreadedEchoServer(context=server_context) as server:
3935 with client_context.wrap_socket(socket.socket(),
3936 server_hostname=hostname) as s:
3937 s.connect((HOST, server.port))
3938 self.assertEqual(s.version(), 'TLSv1.2')
3939
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003940 @requires_tls_version('TLSv1_1')
Christian Heimes2875c602021-04-19 07:27:10 +02003941 @ignore_deprecation
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003942 def test_min_max_version_tlsv1_1(self):
3943 client_context, server_context, hostname = testing_context()
Christian Heimes698dde12018-02-27 11:54:43 +01003944 # client 1.0 to 1.2, server 1.0 to 1.1
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003945 client_context.minimum_version = ssl.TLSVersion.TLSv1
3946 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimes698dde12018-02-27 11:54:43 +01003947 server_context.minimum_version = ssl.TLSVersion.TLSv1
3948 server_context.maximum_version = ssl.TLSVersion.TLSv1_1
Christian Heimesf6c6b582021-03-18 23:06:50 +01003949 seclevel_workaround(client_context, server_context)
Christian Heimes698dde12018-02-27 11:54:43 +01003950
3951 with ThreadedEchoServer(context=server_context) as server:
3952 with client_context.wrap_socket(socket.socket(),
3953 server_hostname=hostname) as s:
3954 s.connect((HOST, server.port))
3955 self.assertEqual(s.version(), 'TLSv1.1')
3956
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003957 @requires_tls_version('TLSv1_2')
Christian Heimesce04e712020-11-18 13:10:53 +01003958 @requires_tls_version('TLSv1')
Christian Heimes2875c602021-04-19 07:27:10 +02003959 @ignore_deprecation
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003960 def test_min_max_version_mismatch(self):
3961 client_context, server_context, hostname = testing_context()
Christian Heimes698dde12018-02-27 11:54:43 +01003962 # client 1.0, server 1.2 (mismatch)
Christian Heimes698dde12018-02-27 11:54:43 +01003963 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesc9bc49c2019-09-11 19:24:47 +02003964 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
Christian Heimese35d1ba2019-06-03 20:40:15 +02003965 client_context.maximum_version = ssl.TLSVersion.TLSv1
Christian Heimesde606ea2019-09-11 19:48:58 +02003966 client_context.minimum_version = ssl.TLSVersion.TLSv1
Christian Heimesf6c6b582021-03-18 23:06:50 +01003967 seclevel_workaround(client_context, server_context)
3968
Christian Heimes698dde12018-02-27 11:54:43 +01003969 with ThreadedEchoServer(context=server_context) as server:
3970 with client_context.wrap_socket(socket.socket(),
3971 server_hostname=hostname) as s:
3972 with self.assertRaises(ssl.SSLError) as e:
3973 s.connect((HOST, server.port))
3974 self.assertIn("alert", str(e.exception))
3975
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003976 @requires_tls_version('SSLv3')
Christian Heimes698dde12018-02-27 11:54:43 +01003977 def test_min_max_version_sslv3(self):
3978 client_context, server_context, hostname = testing_context()
3979 server_context.minimum_version = ssl.TLSVersion.SSLv3
3980 client_context.minimum_version = ssl.TLSVersion.SSLv3
3981 client_context.maximum_version = ssl.TLSVersion.SSLv3
Christian Heimesf6c6b582021-03-18 23:06:50 +01003982 seclevel_workaround(client_context, server_context)
3983
Christian Heimes698dde12018-02-27 11:54:43 +01003984 with ThreadedEchoServer(context=server_context) as server:
3985 with client_context.wrap_socket(socket.socket(),
3986 server_hostname=hostname) as s:
3987 s.connect((HOST, server.port))
3988 self.assertEqual(s.version(), 'SSLv3')
3989
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003990 def test_default_ecdh_curve(self):
3991 # Issue #21015: elliptic curve-based Diffie Hellman key exchange
3992 # should be enabled by default on SSL contexts.
Christian Heimes2875c602021-04-19 07:27:10 +02003993 client_context, server_context, hostname = testing_context()
Christian Heimescb5b68a2017-09-07 18:07:00 -07003994 # TLSv1.3 defaults to PFS key agreement and no longer has KEA in
3995 # cipher name.
Christian Heimes2875c602021-04-19 07:27:10 +02003996 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003997 # Prior to OpenSSL 1.0.0, ECDH ciphers have to be enabled
3998 # explicitly using the 'ECCdraft' cipher alias. Otherwise,
3999 # our default cipher list should prefer ECDH-based ciphers
4000 # automatically.
Christian Heimes2875c602021-04-19 07:27:10 +02004001 with ThreadedEchoServer(context=server_context) as server:
4002 with client_context.wrap_socket(socket.socket(),
4003 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004004 s.connect((HOST, server.port))
4005 self.assertIn("ECDH", s.cipher()[0])
4006
4007 @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES,
4008 "'tls-unique' channel binding not available")
4009 def test_tls_unique_channel_binding(self):
4010 """Test tls-unique channel binding."""
4011 if support.verbose:
4012 sys.stdout.write("\n")
4013
Christian Heimes05d9fe32018-02-27 08:55:39 +01004014 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004015
4016 server = ThreadedEchoServer(context=server_context,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004017 chatty=True,
4018 connectionchatty=False)
Christian Heimes05d9fe32018-02-27 08:55:39 +01004019
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004020 with server:
Christian Heimes05d9fe32018-02-27 08:55:39 +01004021 with client_context.wrap_socket(
4022 socket.socket(),
4023 server_hostname=hostname) as s:
4024 s.connect((HOST, server.port))
4025 # get the data
4026 cb_data = s.get_channel_binding("tls-unique")
4027 if support.verbose:
4028 sys.stdout.write(
4029 " got channel binding data: {0!r}\n".format(cb_data))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004030
Christian Heimes05d9fe32018-02-27 08:55:39 +01004031 # check if it is sane
4032 self.assertIsNotNone(cb_data)
Christian Heimes529525f2018-05-23 22:24:45 +02004033 if s.version() == 'TLSv1.3':
4034 self.assertEqual(len(cb_data), 48)
4035 else:
4036 self.assertEqual(len(cb_data), 12) # True for TLSv1
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004037
Christian Heimes05d9fe32018-02-27 08:55:39 +01004038 # and compare with the peers version
4039 s.write(b"CB tls-unique\n")
4040 peer_data_repr = s.read().strip()
4041 self.assertEqual(peer_data_repr,
4042 repr(cb_data).encode("us-ascii"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004043
4044 # now, again
Christian Heimes05d9fe32018-02-27 08:55:39 +01004045 with client_context.wrap_socket(
4046 socket.socket(),
4047 server_hostname=hostname) as s:
4048 s.connect((HOST, server.port))
4049 new_cb_data = s.get_channel_binding("tls-unique")
4050 if support.verbose:
4051 sys.stdout.write(
4052 "got another channel binding data: {0!r}\n".format(
4053 new_cb_data)
4054 )
4055 # is it really unique
4056 self.assertNotEqual(cb_data, new_cb_data)
4057 self.assertIsNotNone(cb_data)
Christian Heimes529525f2018-05-23 22:24:45 +02004058 if s.version() == 'TLSv1.3':
4059 self.assertEqual(len(cb_data), 48)
4060 else:
4061 self.assertEqual(len(cb_data), 12) # True for TLSv1
Christian Heimes05d9fe32018-02-27 08:55:39 +01004062 s.write(b"CB tls-unique\n")
4063 peer_data_repr = s.read().strip()
4064 self.assertEqual(peer_data_repr,
4065 repr(new_cb_data).encode("us-ascii"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004066
4067 def test_compression(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004068 client_context, server_context, hostname = testing_context()
4069 stats = server_params_test(client_context, server_context,
4070 chatty=True, connectionchatty=True,
4071 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004072 if support.verbose:
4073 sys.stdout.write(" got compression: {!r}\n".format(stats['compression']))
4074 self.assertIn(stats['compression'], { None, 'ZLIB', 'RLE' })
4075
4076 @unittest.skipUnless(hasattr(ssl, 'OP_NO_COMPRESSION'),
4077 "ssl.OP_NO_COMPRESSION needed for this test")
4078 def test_compression_disabled(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004079 client_context, server_context, hostname = testing_context()
4080 client_context.options |= ssl.OP_NO_COMPRESSION
4081 server_context.options |= ssl.OP_NO_COMPRESSION
4082 stats = server_params_test(client_context, server_context,
4083 chatty=True, connectionchatty=True,
4084 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004085 self.assertIs(stats['compression'], None)
4086
Paul Monsonf3550692019-06-19 13:09:54 -07004087 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004088 def test_dh_params(self):
4089 # Check we can get a connection with ephemeral Diffie-Hellman
Christian Heimesa170fa12017-09-15 20:27:30 +02004090 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004091 # test scenario needs TLS <= 1.2
Miss Islington (bot)4becc562021-06-13 05:07:00 -07004092 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesa170fa12017-09-15 20:27:30 +02004093 server_context.load_dh_params(DHFILE)
4094 server_context.set_ciphers("kEDH")
Miss Islington (bot)4becc562021-06-13 05:07:00 -07004095 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesa170fa12017-09-15 20:27:30 +02004096 stats = server_params_test(client_context, server_context,
4097 chatty=True, connectionchatty=True,
4098 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004099 cipher = stats["cipher"][0]
4100 parts = cipher.split("-")
4101 if "ADH" not in parts and "EDH" not in parts and "DHE" not in parts:
4102 self.fail("Non-DH cipher: " + cipher[0])
4103
Christian Heimesb7b92252018-02-25 09:49:31 +01004104 def test_ecdh_curve(self):
4105 # server secp384r1, client auto
4106 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004107
Christian Heimesb7b92252018-02-25 09:49:31 +01004108 server_context.set_ecdh_curve("secp384r1")
4109 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
Christian Heimesd37b74f2021-04-19 08:31:29 +02004110 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesb7b92252018-02-25 09:49:31 +01004111 stats = server_params_test(client_context, server_context,
4112 chatty=True, connectionchatty=True,
4113 sni_name=hostname)
4114
4115 # server auto, client secp384r1
4116 client_context, server_context, hostname = testing_context()
4117 client_context.set_ecdh_curve("secp384r1")
4118 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
Christian Heimesd37b74f2021-04-19 08:31:29 +02004119 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesb7b92252018-02-25 09:49:31 +01004120 stats = server_params_test(client_context, server_context,
4121 chatty=True, connectionchatty=True,
4122 sni_name=hostname)
4123
4124 # server / client curve mismatch
4125 client_context, server_context, hostname = testing_context()
4126 client_context.set_ecdh_curve("prime256v1")
4127 server_context.set_ecdh_curve("secp384r1")
4128 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
Christian Heimesd37b74f2021-04-19 08:31:29 +02004129 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
4130 with self.assertRaises(ssl.SSLError):
Christian Heimes39258d32021-04-17 11:36:35 +02004131 server_params_test(client_context, server_context,
4132 chatty=True, connectionchatty=True,
4133 sni_name=hostname)
Christian Heimesb7b92252018-02-25 09:49:31 +01004134
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004135 def test_selected_alpn_protocol(self):
4136 # selected_alpn_protocol() is None unless ALPN is used.
Christian Heimesa170fa12017-09-15 20:27:30 +02004137 client_context, server_context, hostname = testing_context()
4138 stats = server_params_test(client_context, server_context,
4139 chatty=True, connectionchatty=True,
4140 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004141 self.assertIs(stats['client_alpn_protocol'], None)
4142
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004143 def test_selected_alpn_protocol_if_server_uses_alpn(self):
4144 # selected_alpn_protocol() is None unless ALPN is used by the client.
Christian Heimesa170fa12017-09-15 20:27:30 +02004145 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004146 server_context.set_alpn_protocols(['foo', 'bar'])
4147 stats = server_params_test(client_context, server_context,
Christian Heimesa170fa12017-09-15 20:27:30 +02004148 chatty=True, connectionchatty=True,
4149 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004150 self.assertIs(stats['client_alpn_protocol'], None)
4151
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004152 def test_alpn_protocols(self):
4153 server_protocols = ['foo', 'bar', 'milkshake']
4154 protocol_tests = [
4155 (['foo', 'bar'], 'foo'),
4156 (['bar', 'foo'], 'foo'),
4157 (['milkshake'], 'milkshake'),
4158 (['http/3.0', 'http/4.0'], None)
4159 ]
4160 for client_protocols, expected in protocol_tests:
Christian Heimesa170fa12017-09-15 20:27:30 +02004161 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004162 server_context.set_alpn_protocols(server_protocols)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004163 client_context.set_alpn_protocols(client_protocols)
4164
4165 try:
4166 stats = server_params_test(client_context,
4167 server_context,
4168 chatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02004169 connectionchatty=True,
4170 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004171 except ssl.SSLError as e:
4172 stats = e
4173
Christian Heimes39258d32021-04-17 11:36:35 +02004174 msg = "failed trying %s (s) and %s (c).\n" \
4175 "was expecting %s, but got %%s from the %%s" \
4176 % (str(server_protocols), str(client_protocols),
4177 str(expected))
4178 client_result = stats['client_alpn_protocol']
4179 self.assertEqual(client_result, expected,
4180 msg % (client_result, "client"))
4181 server_result = stats['server_alpn_protocols'][-1] \
4182 if len(stats['server_alpn_protocols']) else 'nothing'
4183 self.assertEqual(server_result, expected,
4184 msg % (server_result, "server"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004185
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004186 def test_npn_protocols(self):
Christian Heimes39258d32021-04-17 11:36:35 +02004187 assert not ssl.HAS_NPN
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004188
4189 def sni_contexts(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004190 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004191 server_context.load_cert_chain(SIGNED_CERTFILE)
Christian Heimesa170fa12017-09-15 20:27:30 +02004192 other_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004193 other_context.load_cert_chain(SIGNED_CERTFILE2)
Christian Heimesa170fa12017-09-15 20:27:30 +02004194 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004195 client_context.load_verify_locations(SIGNING_CA)
4196 return server_context, other_context, client_context
4197
4198 def check_common_name(self, stats, name):
4199 cert = stats['peercert']
4200 self.assertIn((('commonName', name),), cert['subject'])
4201
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004202 def test_sni_callback(self):
4203 calls = []
4204 server_context, other_context, client_context = self.sni_contexts()
4205
Christian Heimesa170fa12017-09-15 20:27:30 +02004206 client_context.check_hostname = False
4207
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004208 def servername_cb(ssl_sock, server_name, initial_context):
4209 calls.append((server_name, initial_context))
4210 if server_name is not None:
4211 ssl_sock.context = other_context
4212 server_context.set_servername_callback(servername_cb)
4213
4214 stats = server_params_test(client_context, server_context,
4215 chatty=True,
4216 sni_name='supermessage')
4217 # The hostname was fetched properly, and the certificate was
4218 # changed for the connection.
4219 self.assertEqual(calls, [("supermessage", server_context)])
4220 # CERTFILE4 was selected
4221 self.check_common_name(stats, 'fakehostname')
4222
4223 calls = []
4224 # The callback is called with server_name=None
4225 stats = server_params_test(client_context, server_context,
4226 chatty=True,
4227 sni_name=None)
4228 self.assertEqual(calls, [(None, server_context)])
Christian Heimesa170fa12017-09-15 20:27:30 +02004229 self.check_common_name(stats, SIGNED_CERTFILE_HOSTNAME)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004230
4231 # Check disabling the callback
4232 calls = []
4233 server_context.set_servername_callback(None)
4234
4235 stats = server_params_test(client_context, server_context,
4236 chatty=True,
4237 sni_name='notfunny')
4238 # Certificate didn't change
Christian Heimesa170fa12017-09-15 20:27:30 +02004239 self.check_common_name(stats, SIGNED_CERTFILE_HOSTNAME)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004240 self.assertEqual(calls, [])
4241
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004242 def test_sni_callback_alert(self):
4243 # Returning a TLS alert is reflected to the connecting client
4244 server_context, other_context, client_context = self.sni_contexts()
4245
4246 def cb_returning_alert(ssl_sock, server_name, initial_context):
4247 return ssl.ALERT_DESCRIPTION_ACCESS_DENIED
4248 server_context.set_servername_callback(cb_returning_alert)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004249 with self.assertRaises(ssl.SSLError) as cm:
4250 stats = server_params_test(client_context, server_context,
4251 chatty=False,
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004252 sni_name='supermessage')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004253 self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_ACCESS_DENIED')
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004254
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004255 def test_sni_callback_raising(self):
4256 # Raising fails the connection with a TLS handshake failure alert.
4257 server_context, other_context, client_context = self.sni_contexts()
4258
4259 def cb_raising(ssl_sock, server_name, initial_context):
4260 1/0
4261 server_context.set_servername_callback(cb_raising)
4262
Victor Stinner00253502019-06-03 03:51:43 +02004263 with support.catch_unraisable_exception() as catch:
4264 with self.assertRaises(ssl.SSLError) as cm:
4265 stats = server_params_test(client_context, server_context,
4266 chatty=False,
4267 sni_name='supermessage')
4268
4269 self.assertEqual(cm.exception.reason,
4270 'SSLV3_ALERT_HANDSHAKE_FAILURE')
4271 self.assertEqual(catch.unraisable.exc_type, ZeroDivisionError)
Antoine Pitrou50b24d02013-04-11 20:48:42 +02004272
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004273 def test_sni_callback_wrong_return_type(self):
4274 # Returning the wrong return type terminates the TLS connection
4275 # with an internal error alert.
4276 server_context, other_context, client_context = self.sni_contexts()
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004277
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004278 def cb_wrong_return_type(ssl_sock, server_name, initial_context):
4279 return "foo"
4280 server_context.set_servername_callback(cb_wrong_return_type)
4281
Victor Stinner00253502019-06-03 03:51:43 +02004282 with support.catch_unraisable_exception() as catch:
4283 with self.assertRaises(ssl.SSLError) as cm:
4284 stats = server_params_test(client_context, server_context,
4285 chatty=False,
4286 sni_name='supermessage')
4287
4288
4289 self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_INTERNAL_ERROR')
4290 self.assertEqual(catch.unraisable.exc_type, TypeError)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004291
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004292 def test_shared_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004293 client_context, server_context, hostname = testing_context()
Christian Heimese8eb6cb2018-05-22 22:50:12 +02004294 client_context.set_ciphers("AES128:AES256")
4295 server_context.set_ciphers("AES256")
4296 expected_algs = [
4297 "AES256", "AES-256",
4298 # TLS 1.3 ciphers are always enabled
4299 "TLS_CHACHA20", "TLS_AES",
4300 ]
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004301
Christian Heimesa170fa12017-09-15 20:27:30 +02004302 stats = server_params_test(client_context, server_context,
4303 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004304 ciphers = stats['server_shared_ciphers'][0]
4305 self.assertGreater(len(ciphers), 0)
4306 for name, tls_version, bits in ciphers:
Christian Heimese8eb6cb2018-05-22 22:50:12 +02004307 if not any(alg in name for alg in expected_algs):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004308 self.fail(name)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004309
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004310 def test_read_write_after_close_raises_valuerror(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004311 client_context, server_context, hostname = testing_context()
4312 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004313
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004314 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02004315 s = client_context.wrap_socket(socket.socket(),
4316 server_hostname=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004317 s.connect((HOST, server.port))
4318 s.close()
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004319
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004320 self.assertRaises(ValueError, s.read, 1024)
4321 self.assertRaises(ValueError, s.write, b'hello')
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004322
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004323 def test_sendfile(self):
4324 TEST_DATA = b"x" * 512
Hai Shia7f5d932020-08-04 00:41:24 +08004325 with open(os_helper.TESTFN, 'wb') as f:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004326 f.write(TEST_DATA)
Hai Shia7f5d932020-08-04 00:41:24 +08004327 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimes2875c602021-04-19 07:27:10 +02004328 client_context, server_context, hostname = testing_context()
4329 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004330 with server:
Christian Heimes2875c602021-04-19 07:27:10 +02004331 with client_context.wrap_socket(socket.socket(),
4332 server_hostname=hostname) as s:
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004333 s.connect((HOST, server.port))
Hai Shia7f5d932020-08-04 00:41:24 +08004334 with open(os_helper.TESTFN, 'rb') as file:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004335 s.sendfile(file)
4336 self.assertEqual(s.recv(1024), TEST_DATA)
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004337
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004338 def test_session(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004339 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004340 # TODO: sessions aren't compatible with TLSv1.3 yet
Miss Islington (bot)4becc562021-06-13 05:07:00 -07004341 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004342
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004343 # first connection without session
Christian Heimesa170fa12017-09-15 20:27:30 +02004344 stats = server_params_test(client_context, server_context,
4345 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004346 session = stats['session']
4347 self.assertTrue(session.id)
4348 self.assertGreater(session.time, 0)
4349 self.assertGreater(session.timeout, 0)
4350 self.assertTrue(session.has_ticket)
Christian Heimes39258d32021-04-17 11:36:35 +02004351 self.assertGreater(session.ticket_lifetime_hint, 0)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004352 self.assertFalse(stats['session_reused'])
4353 sess_stat = server_context.session_stats()
4354 self.assertEqual(sess_stat['accept'], 1)
4355 self.assertEqual(sess_stat['hits'], 0)
Giampaolo Rodola'915d1412014-06-11 03:54:30 +02004356
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004357 # reuse session
Christian Heimesa170fa12017-09-15 20:27:30 +02004358 stats = server_params_test(client_context, server_context,
4359 session=session, sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004360 sess_stat = server_context.session_stats()
4361 self.assertEqual(sess_stat['accept'], 2)
4362 self.assertEqual(sess_stat['hits'], 1)
4363 self.assertTrue(stats['session_reused'])
4364 session2 = stats['session']
4365 self.assertEqual(session2.id, session.id)
4366 self.assertEqual(session2, session)
4367 self.assertIsNot(session2, session)
4368 self.assertGreaterEqual(session2.time, session.time)
4369 self.assertGreaterEqual(session2.timeout, session.timeout)
Christian Heimes99a65702016-09-10 23:44:53 +02004370
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004371 # another one without session
Christian Heimesa170fa12017-09-15 20:27:30 +02004372 stats = server_params_test(client_context, server_context,
4373 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004374 self.assertFalse(stats['session_reused'])
4375 session3 = stats['session']
4376 self.assertNotEqual(session3.id, session.id)
4377 self.assertNotEqual(session3, session)
4378 sess_stat = server_context.session_stats()
4379 self.assertEqual(sess_stat['accept'], 3)
4380 self.assertEqual(sess_stat['hits'], 1)
Christian Heimes99a65702016-09-10 23:44:53 +02004381
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004382 # reuse session again
Christian Heimesa170fa12017-09-15 20:27:30 +02004383 stats = server_params_test(client_context, server_context,
4384 session=session, sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004385 self.assertTrue(stats['session_reused'])
4386 session4 = stats['session']
4387 self.assertEqual(session4.id, session.id)
4388 self.assertEqual(session4, session)
4389 self.assertGreaterEqual(session4.time, session.time)
4390 self.assertGreaterEqual(session4.timeout, session.timeout)
4391 sess_stat = server_context.session_stats()
4392 self.assertEqual(sess_stat['accept'], 4)
4393 self.assertEqual(sess_stat['hits'], 2)
Christian Heimes99a65702016-09-10 23:44:53 +02004394
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004395 def test_session_handling(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004396 client_context, server_context, hostname = testing_context()
4397 client_context2, _, _ = testing_context()
Christian Heimes99a65702016-09-10 23:44:53 +02004398
Christian Heimes05d9fe32018-02-27 08:55:39 +01004399 # TODO: session reuse does not work with TLSv1.3
Miss Islington (bot)4becc562021-06-13 05:07:00 -07004400 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
4401 client_context2.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimescb5b68a2017-09-07 18:07:00 -07004402
Christian Heimesa170fa12017-09-15 20:27:30 +02004403 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004404 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02004405 with client_context.wrap_socket(socket.socket(),
4406 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004407 # session is None before handshake
4408 self.assertEqual(s.session, None)
4409 self.assertEqual(s.session_reused, None)
4410 s.connect((HOST, server.port))
4411 session = s.session
4412 self.assertTrue(session)
4413 with self.assertRaises(TypeError) as e:
4414 s.session = object
Ned Deily4531ec72018-06-11 20:26:28 -04004415 self.assertEqual(str(e.exception), 'Value is not a SSLSession.')
Christian Heimes99a65702016-09-10 23:44:53 +02004416
Christian Heimesa170fa12017-09-15 20:27:30 +02004417 with client_context.wrap_socket(socket.socket(),
4418 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004419 s.connect((HOST, server.port))
4420 # cannot set session after handshake
4421 with self.assertRaises(ValueError) as e:
4422 s.session = session
4423 self.assertEqual(str(e.exception),
4424 'Cannot set session after handshake.')
Christian Heimes99a65702016-09-10 23:44:53 +02004425
Christian Heimesa170fa12017-09-15 20:27:30 +02004426 with client_context.wrap_socket(socket.socket(),
4427 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004428 # can set session before handshake and before the
4429 # connection was established
4430 s.session = session
4431 s.connect((HOST, server.port))
4432 self.assertEqual(s.session.id, session.id)
4433 self.assertEqual(s.session, session)
4434 self.assertEqual(s.session_reused, True)
Christian Heimes99a65702016-09-10 23:44:53 +02004435
Christian Heimesa170fa12017-09-15 20:27:30 +02004436 with client_context2.wrap_socket(socket.socket(),
4437 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004438 # cannot re-use session with a different SSLContext
4439 with self.assertRaises(ValueError) as e:
Christian Heimes99a65702016-09-10 23:44:53 +02004440 s.session = session
4441 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004442 self.assertEqual(str(e.exception),
4443 'Session refers to a different SSLContext.')
Christian Heimes99a65702016-09-10 23:44:53 +02004444
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01004445
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02004446@unittest.skipUnless(has_tls_version('TLSv1_3'), "Test needs TLS 1.3")
Christian Heimes9fb051f2018-09-23 08:32:31 +02004447class TestPostHandshakeAuth(unittest.TestCase):
4448 def test_pha_setter(self):
4449 protocols = [
Christian Heimes2875c602021-04-19 07:27:10 +02004450 ssl.PROTOCOL_TLS_SERVER, ssl.PROTOCOL_TLS_CLIENT
Christian Heimes9fb051f2018-09-23 08:32:31 +02004451 ]
4452 for protocol in protocols:
4453 ctx = ssl.SSLContext(protocol)
4454 self.assertEqual(ctx.post_handshake_auth, False)
4455
4456 ctx.post_handshake_auth = True
4457 self.assertEqual(ctx.post_handshake_auth, True)
4458
4459 ctx.verify_mode = ssl.CERT_REQUIRED
4460 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
4461 self.assertEqual(ctx.post_handshake_auth, True)
4462
4463 ctx.post_handshake_auth = False
4464 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
4465 self.assertEqual(ctx.post_handshake_auth, False)
4466
4467 ctx.verify_mode = ssl.CERT_OPTIONAL
4468 ctx.post_handshake_auth = True
4469 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
4470 self.assertEqual(ctx.post_handshake_auth, True)
4471
4472 def test_pha_required(self):
4473 client_context, server_context, hostname = testing_context()
4474 server_context.post_handshake_auth = True
4475 server_context.verify_mode = ssl.CERT_REQUIRED
4476 client_context.post_handshake_auth = True
4477 client_context.load_cert_chain(SIGNED_CERTFILE)
4478
4479 server = ThreadedEchoServer(context=server_context, chatty=False)
4480 with server:
4481 with client_context.wrap_socket(socket.socket(),
4482 server_hostname=hostname) as s:
4483 s.connect((HOST, server.port))
4484 s.write(b'HASCERT')
4485 self.assertEqual(s.recv(1024), b'FALSE\n')
4486 s.write(b'PHA')
4487 self.assertEqual(s.recv(1024), b'OK\n')
4488 s.write(b'HASCERT')
4489 self.assertEqual(s.recv(1024), b'TRUE\n')
4490 # PHA method just returns true when cert is already available
4491 s.write(b'PHA')
4492 self.assertEqual(s.recv(1024), b'OK\n')
4493 s.write(b'GETCERT')
4494 cert_text = s.recv(4096).decode('us-ascii')
4495 self.assertIn('Python Software Foundation CA', cert_text)
4496
4497 def test_pha_required_nocert(self):
4498 client_context, server_context, hostname = testing_context()
4499 server_context.post_handshake_auth = True
4500 server_context.verify_mode = ssl.CERT_REQUIRED
4501 client_context.post_handshake_auth = True
4502
Christian Heimesc8666cf2021-04-24 09:17:54 +02004503 def msg_cb(conn, direction, version, content_type, msg_type, data):
4504 if support.verbose and content_type == _TLSContentType.ALERT:
4505 info = (conn, direction, version, content_type, msg_type, data)
4506 sys.stdout.write(f"TLS: {info!r}\n")
4507
4508 server_context._msg_callback = msg_cb
4509 client_context._msg_callback = msg_cb
4510
4511 server = ThreadedEchoServer(context=server_context, chatty=True)
4512 with server:
4513 with client_context.wrap_socket(socket.socket(),
Miss Islington (bot)d2ab15f2021-06-03 13:15:15 -07004514 server_hostname=hostname,
4515 suppress_ragged_eofs=False) as s:
Christian Heimesc8666cf2021-04-24 09:17:54 +02004516 s.connect((HOST, server.port))
4517 s.write(b'PHA')
Christian Heimesce9a0642021-04-24 15:08:13 +02004518 # test sometimes fails with EOF error. Test passes as long as
4519 # server aborts connection with an error.
Christian Heimesc8666cf2021-04-24 09:17:54 +02004520 with self.assertRaisesRegex(
4521 ssl.SSLError,
Christian Heimesce9a0642021-04-24 15:08:13 +02004522 '(certificate required|EOF occurred)'
Christian Heimesc8666cf2021-04-24 09:17:54 +02004523 ):
Victor Stinner73ea5462019-07-09 14:33:49 +02004524 # receive CertificateRequest
Miss Islington (bot)e5e93e62021-06-02 16:48:40 -07004525 data = s.recv(1024)
Miss Islington (bot)e5e93e62021-06-02 16:48:40 -07004526 self.assertEqual(data, b'OK\n')
4527
Victor Stinner73ea5462019-07-09 14:33:49 +02004528 # send empty Certificate + Finish
4529 s.write(b'HASCERT')
Miss Islington (bot)e5e93e62021-06-02 16:48:40 -07004530
Victor Stinner73ea5462019-07-09 14:33:49 +02004531 # receive alert
Miss Islington (bot)d2ab15f2021-06-03 13:15:15 -07004532 s.recv(1024)
Christian Heimes9fb051f2018-09-23 08:32:31 +02004533
4534 def test_pha_optional(self):
4535 if support.verbose:
4536 sys.stdout.write("\n")
4537
4538 client_context, server_context, hostname = testing_context()
4539 server_context.post_handshake_auth = True
4540 server_context.verify_mode = ssl.CERT_REQUIRED
4541 client_context.post_handshake_auth = True
4542 client_context.load_cert_chain(SIGNED_CERTFILE)
4543
4544 # check CERT_OPTIONAL
4545 server_context.verify_mode = ssl.CERT_OPTIONAL
4546 server = ThreadedEchoServer(context=server_context, chatty=False)
4547 with server:
4548 with client_context.wrap_socket(socket.socket(),
4549 server_hostname=hostname) as s:
4550 s.connect((HOST, server.port))
4551 s.write(b'HASCERT')
4552 self.assertEqual(s.recv(1024), b'FALSE\n')
4553 s.write(b'PHA')
4554 self.assertEqual(s.recv(1024), b'OK\n')
4555 s.write(b'HASCERT')
4556 self.assertEqual(s.recv(1024), b'TRUE\n')
4557
4558 def test_pha_optional_nocert(self):
4559 if support.verbose:
4560 sys.stdout.write("\n")
4561
4562 client_context, server_context, hostname = testing_context()
4563 server_context.post_handshake_auth = True
4564 server_context.verify_mode = ssl.CERT_OPTIONAL
4565 client_context.post_handshake_auth = True
4566
4567 server = ThreadedEchoServer(context=server_context, chatty=False)
4568 with server:
4569 with client_context.wrap_socket(socket.socket(),
4570 server_hostname=hostname) as s:
4571 s.connect((HOST, server.port))
4572 s.write(b'HASCERT')
4573 self.assertEqual(s.recv(1024), b'FALSE\n')
4574 s.write(b'PHA')
4575 self.assertEqual(s.recv(1024), b'OK\n')
penguindustin96466302019-05-06 14:57:17 -04004576 # optional doesn't fail when client does not have a cert
Christian Heimes9fb051f2018-09-23 08:32:31 +02004577 s.write(b'HASCERT')
4578 self.assertEqual(s.recv(1024), b'FALSE\n')
4579
4580 def test_pha_no_pha_client(self):
4581 client_context, server_context, hostname = testing_context()
4582 server_context.post_handshake_auth = True
4583 server_context.verify_mode = ssl.CERT_REQUIRED
4584 client_context.load_cert_chain(SIGNED_CERTFILE)
4585
4586 server = ThreadedEchoServer(context=server_context, chatty=False)
4587 with server:
4588 with client_context.wrap_socket(socket.socket(),
4589 server_hostname=hostname) as s:
4590 s.connect((HOST, server.port))
4591 with self.assertRaisesRegex(ssl.SSLError, 'not server'):
4592 s.verify_client_post_handshake()
4593 s.write(b'PHA')
4594 self.assertIn(b'extension not received', s.recv(1024))
4595
4596 def test_pha_no_pha_server(self):
4597 # server doesn't have PHA enabled, cert is requested in handshake
4598 client_context, server_context, hostname = testing_context()
4599 server_context.verify_mode = ssl.CERT_REQUIRED
4600 client_context.post_handshake_auth = True
4601 client_context.load_cert_chain(SIGNED_CERTFILE)
4602
4603 server = ThreadedEchoServer(context=server_context, chatty=False)
4604 with server:
4605 with client_context.wrap_socket(socket.socket(),
4606 server_hostname=hostname) as s:
4607 s.connect((HOST, server.port))
4608 s.write(b'HASCERT')
4609 self.assertEqual(s.recv(1024), b'TRUE\n')
4610 # PHA doesn't fail if there is already a cert
4611 s.write(b'PHA')
4612 self.assertEqual(s.recv(1024), b'OK\n')
4613 s.write(b'HASCERT')
4614 self.assertEqual(s.recv(1024), b'TRUE\n')
4615
4616 def test_pha_not_tls13(self):
4617 # TLS 1.2
4618 client_context, server_context, hostname = testing_context()
4619 server_context.verify_mode = ssl.CERT_REQUIRED
4620 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
4621 client_context.post_handshake_auth = True
4622 client_context.load_cert_chain(SIGNED_CERTFILE)
4623
4624 server = ThreadedEchoServer(context=server_context, chatty=False)
4625 with server:
4626 with client_context.wrap_socket(socket.socket(),
4627 server_hostname=hostname) as s:
4628 s.connect((HOST, server.port))
4629 # PHA fails for TLS != 1.3
4630 s.write(b'PHA')
4631 self.assertIn(b'WRONG_SSL_VERSION', s.recv(1024))
4632
Christian Heimesf0f59302019-07-01 08:29:17 +02004633 def test_bpo37428_pha_cert_none(self):
4634 # verify that post_handshake_auth does not implicitly enable cert
4635 # validation.
4636 hostname = SIGNED_CERTFILE_HOSTNAME
4637 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4638 client_context.post_handshake_auth = True
4639 client_context.load_cert_chain(SIGNED_CERTFILE)
4640 # no cert validation and CA on client side
4641 client_context.check_hostname = False
4642 client_context.verify_mode = ssl.CERT_NONE
4643
4644 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
4645 server_context.load_cert_chain(SIGNED_CERTFILE)
4646 server_context.load_verify_locations(SIGNING_CA)
4647 server_context.post_handshake_auth = True
4648 server_context.verify_mode = ssl.CERT_REQUIRED
4649
4650 server = ThreadedEchoServer(context=server_context, chatty=False)
4651 with server:
4652 with client_context.wrap_socket(socket.socket(),
4653 server_hostname=hostname) as s:
4654 s.connect((HOST, server.port))
4655 s.write(b'HASCERT')
4656 self.assertEqual(s.recv(1024), b'FALSE\n')
4657 s.write(b'PHA')
4658 self.assertEqual(s.recv(1024), b'OK\n')
4659 s.write(b'HASCERT')
4660 self.assertEqual(s.recv(1024), b'TRUE\n')
4661 # server cert has not been validated
4662 self.assertEqual(s.getpeercert(), {})
4663
Christian Heimes666991f2021-04-26 15:01:40 +02004664 def test_internal_chain_client(self):
4665 client_context, server_context, hostname = testing_context(
4666 server_chain=False
4667 )
4668 server = ThreadedEchoServer(context=server_context, chatty=False)
4669 with server:
4670 with client_context.wrap_socket(
4671 socket.socket(),
4672 server_hostname=hostname
4673 ) as s:
4674 s.connect((HOST, server.port))
4675 vc = s._sslobj.get_verified_chain()
4676 self.assertEqual(len(vc), 2)
4677 ee, ca = vc
4678 uvc = s._sslobj.get_unverified_chain()
4679 self.assertEqual(len(uvc), 1)
4680
4681 self.assertEqual(ee, uvc[0])
4682 self.assertEqual(hash(ee), hash(uvc[0]))
4683 self.assertEqual(repr(ee), repr(uvc[0]))
4684
4685 self.assertNotEqual(ee, ca)
4686 self.assertNotEqual(hash(ee), hash(ca))
4687 self.assertNotEqual(repr(ee), repr(ca))
4688 self.assertNotEqual(ee.get_info(), ca.get_info())
4689 self.assertIn("CN=localhost", repr(ee))
4690 self.assertIn("CN=our-ca-server", repr(ca))
4691
4692 pem = ee.public_bytes(_ssl.ENCODING_PEM)
4693 der = ee.public_bytes(_ssl.ENCODING_DER)
4694 self.assertIsInstance(pem, str)
4695 self.assertIn("-----BEGIN CERTIFICATE-----", pem)
4696 self.assertIsInstance(der, bytes)
4697 self.assertEqual(
4698 ssl.PEM_cert_to_DER_cert(pem), der
4699 )
4700
4701 def test_internal_chain_server(self):
4702 client_context, server_context, hostname = testing_context()
4703 client_context.load_cert_chain(SIGNED_CERTFILE)
4704 server_context.verify_mode = ssl.CERT_REQUIRED
4705 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
4706
4707 server = ThreadedEchoServer(context=server_context, chatty=False)
4708 with server:
4709 with client_context.wrap_socket(
4710 socket.socket(),
4711 server_hostname=hostname
4712 ) as s:
4713 s.connect((HOST, server.port))
4714 s.write(b'VERIFIEDCHAIN\n')
4715 res = s.recv(1024)
4716 self.assertEqual(res, b'\x02\n')
4717 s.write(b'UNVERIFIEDCHAIN\n')
4718 res = s.recv(1024)
4719 self.assertEqual(res, b'\x02\n')
4720
Christian Heimes9fb051f2018-09-23 08:32:31 +02004721
Christian Heimesc7f70692019-05-31 11:44:05 +02004722HAS_KEYLOG = hasattr(ssl.SSLContext, 'keylog_filename')
4723requires_keylog = unittest.skipUnless(
4724 HAS_KEYLOG, 'test requires OpenSSL 1.1.1 with keylog callback')
4725
4726class TestSSLDebug(unittest.TestCase):
4727
Hai Shia7f5d932020-08-04 00:41:24 +08004728 def keylog_lines(self, fname=os_helper.TESTFN):
Christian Heimesc7f70692019-05-31 11:44:05 +02004729 with open(fname) as f:
4730 return len(list(f))
4731
4732 @requires_keylog
Paul Monsonf3550692019-06-19 13:09:54 -07004733 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004734 def test_keylog_defaults(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004735 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004736 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4737 self.assertEqual(ctx.keylog_filename, None)
4738
Hai Shia7f5d932020-08-04 00:41:24 +08004739 self.assertFalse(os.path.isfile(os_helper.TESTFN))
4740 ctx.keylog_filename = os_helper.TESTFN
4741 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
4742 self.assertTrue(os.path.isfile(os_helper.TESTFN))
Christian Heimesc7f70692019-05-31 11:44:05 +02004743 self.assertEqual(self.keylog_lines(), 1)
4744
4745 ctx.keylog_filename = None
4746 self.assertEqual(ctx.keylog_filename, None)
4747
4748 with self.assertRaises((IsADirectoryError, PermissionError)):
4749 # Windows raises PermissionError
4750 ctx.keylog_filename = os.path.dirname(
Hai Shia7f5d932020-08-04 00:41:24 +08004751 os.path.abspath(os_helper.TESTFN))
Christian Heimesc7f70692019-05-31 11:44:05 +02004752
4753 with self.assertRaises(TypeError):
4754 ctx.keylog_filename = 1
4755
4756 @requires_keylog
Paul Monsonf3550692019-06-19 13:09:54 -07004757 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004758 def test_keylog_filename(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004759 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004760 client_context, server_context, hostname = testing_context()
4761
Hai Shia7f5d932020-08-04 00:41:24 +08004762 client_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004763 server = ThreadedEchoServer(context=server_context, chatty=False)
4764 with server:
4765 with client_context.wrap_socket(socket.socket(),
4766 server_hostname=hostname) as s:
4767 s.connect((HOST, server.port))
4768 # header, 5 lines for TLS 1.3
4769 self.assertEqual(self.keylog_lines(), 6)
4770
4771 client_context.keylog_filename = None
Hai Shia7f5d932020-08-04 00:41:24 +08004772 server_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004773 server = ThreadedEchoServer(context=server_context, chatty=False)
4774 with server:
4775 with client_context.wrap_socket(socket.socket(),
4776 server_hostname=hostname) as s:
4777 s.connect((HOST, server.port))
4778 self.assertGreaterEqual(self.keylog_lines(), 11)
4779
Hai Shia7f5d932020-08-04 00:41:24 +08004780 client_context.keylog_filename = os_helper.TESTFN
4781 server_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004782 server = ThreadedEchoServer(context=server_context, chatty=False)
4783 with server:
4784 with client_context.wrap_socket(socket.socket(),
4785 server_hostname=hostname) as s:
4786 s.connect((HOST, server.port))
4787 self.assertGreaterEqual(self.keylog_lines(), 21)
4788
4789 client_context.keylog_filename = None
4790 server_context.keylog_filename = None
4791
4792 @requires_keylog
4793 @unittest.skipIf(sys.flags.ignore_environment,
4794 "test is not compatible with ignore_environment")
Paul Monsonf3550692019-06-19 13:09:54 -07004795 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004796 def test_keylog_env(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004797 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004798 with unittest.mock.patch.dict(os.environ):
Hai Shia7f5d932020-08-04 00:41:24 +08004799 os.environ['SSLKEYLOGFILE'] = os_helper.TESTFN
4800 self.assertEqual(os.environ['SSLKEYLOGFILE'], os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004801
4802 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4803 self.assertEqual(ctx.keylog_filename, None)
4804
4805 ctx = ssl.create_default_context()
Hai Shia7f5d932020-08-04 00:41:24 +08004806 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004807
4808 ctx = ssl._create_stdlib_context()
Hai Shia7f5d932020-08-04 00:41:24 +08004809 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004810
4811 def test_msg_callback(self):
4812 client_context, server_context, hostname = testing_context()
4813
4814 def msg_cb(conn, direction, version, content_type, msg_type, data):
4815 pass
4816
4817 self.assertIs(client_context._msg_callback, None)
4818 client_context._msg_callback = msg_cb
4819 self.assertIs(client_context._msg_callback, msg_cb)
4820 with self.assertRaises(TypeError):
4821 client_context._msg_callback = object()
4822
4823 def test_msg_callback_tls12(self):
4824 client_context, server_context, hostname = testing_context()
Miss Islington (bot)4becc562021-06-13 05:07:00 -07004825 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesc7f70692019-05-31 11:44:05 +02004826
4827 msg = []
4828
4829 def msg_cb(conn, direction, version, content_type, msg_type, data):
4830 self.assertIsInstance(conn, ssl.SSLSocket)
4831 self.assertIsInstance(data, bytes)
4832 self.assertIn(direction, {'read', 'write'})
4833 msg.append((direction, version, content_type, msg_type))
4834
4835 client_context._msg_callback = msg_cb
4836
4837 server = ThreadedEchoServer(context=server_context, chatty=False)
4838 with server:
4839 with client_context.wrap_socket(socket.socket(),
4840 server_hostname=hostname) as s:
4841 s.connect((HOST, server.port))
4842
Christian Heimese35d1ba2019-06-03 20:40:15 +02004843 self.assertIn(
Christian Heimesc7f70692019-05-31 11:44:05 +02004844 ("read", TLSVersion.TLSv1_2, _TLSContentType.HANDSHAKE,
4845 _TLSMessageType.SERVER_KEY_EXCHANGE),
Christian Heimese35d1ba2019-06-03 20:40:15 +02004846 msg
4847 )
4848 self.assertIn(
Christian Heimesc7f70692019-05-31 11:44:05 +02004849 ("write", TLSVersion.TLSv1_2, _TLSContentType.CHANGE_CIPHER_SPEC,
4850 _TLSMessageType.CHANGE_CIPHER_SPEC),
Christian Heimese35d1ba2019-06-03 20:40:15 +02004851 msg
4852 )
Christian Heimesc7f70692019-05-31 11:44:05 +02004853
Christian Heimes77cde502021-03-21 16:13:09 +01004854 def test_msg_callback_deadlock_bpo43577(self):
4855 client_context, server_context, hostname = testing_context()
4856 server_context2 = testing_context()[1]
4857
4858 def msg_cb(conn, direction, version, content_type, msg_type, data):
4859 pass
4860
4861 def sni_cb(sock, servername, ctx):
4862 sock.context = server_context2
4863
4864 server_context._msg_callback = msg_cb
4865 server_context.sni_callback = sni_cb
4866
4867 server = ThreadedEchoServer(context=server_context, chatty=False)
4868 with server:
4869 with client_context.wrap_socket(socket.socket(),
4870 server_hostname=hostname) as s:
4871 s.connect((HOST, server.port))
4872 with client_context.wrap_socket(socket.socket(),
4873 server_hostname=hostname) as s:
4874 s.connect((HOST, server.port))
4875
Christian Heimesc7f70692019-05-31 11:44:05 +02004876
Serhiy Storchakabedce352021-09-19 22:36:03 +03004877def setUpModule():
Antoine Pitrou15cee622010-08-04 16:45:21 +00004878 if support.verbose:
4879 plats = {
Antoine Pitrou15cee622010-08-04 16:45:21 +00004880 'Mac': platform.mac_ver,
4881 'Windows': platform.win32_ver,
4882 }
Petr Viktorin8b94b412018-05-16 11:51:18 -04004883 for name, func in plats.items():
4884 plat = func()
4885 if plat and plat[0]:
4886 plat = '%s %r' % (name, plat)
4887 break
4888 else:
4889 plat = repr(platform.platform())
Antoine Pitrou15cee622010-08-04 16:45:21 +00004890 print("test_ssl: testing with %r %r" %
4891 (ssl.OPENSSL_VERSION, ssl.OPENSSL_VERSION_INFO))
4892 print(" under %s" % plat)
Antoine Pitroud5323212010-10-22 18:19:07 +00004893 print(" HAS_SNI = %r" % ssl.HAS_SNI)
Antoine Pitrou609ef012013-03-29 18:09:06 +01004894 print(" OP_ALL = 0x%8x" % ssl.OP_ALL)
4895 try:
4896 print(" OP_NO_TLSv1_1 = 0x%8x" % ssl.OP_NO_TLSv1_1)
4897 except AttributeError:
4898 pass
Antoine Pitrou15cee622010-08-04 16:45:21 +00004899
Antoine Pitrou152efa22010-05-16 18:19:27 +00004900 for filename in [
Martin Panter3840b2a2016-03-27 01:53:46 +00004901 CERTFILE, BYTES_CERTFILE,
Antoine Pitrou152efa22010-05-16 18:19:27 +00004902 ONLYCERT, ONLYKEY, BYTES_ONLYCERT, BYTES_ONLYKEY,
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004903 SIGNED_CERTFILE, SIGNED_CERTFILE2, SIGNING_CA,
Antoine Pitrou152efa22010-05-16 18:19:27 +00004904 BADCERT, BADKEY, EMPTYCERT]:
4905 if not os.path.exists(filename):
4906 raise support.TestFailed("Can't read certificate file %r" % filename)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004907
Hai Shie80697d2020-05-28 06:10:27 +08004908 thread_info = threading_helper.threading_setup()
Serhiy Storchakabedce352021-09-19 22:36:03 +03004909 unittest.addModuleCleanup(threading_helper.threading_cleanup, *thread_info)
4910
Thomas Woutersed03b412007-08-28 21:37:11 +00004911
4912if __name__ == "__main__":
Serhiy Storchakabedce352021-09-19 22:36:03 +03004913 unittest.main()