blob: 9bd8e2264c1520f23aa9a376d9b4c3be6be7d485 [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
16import enum
Antoine Pitroucfcd8ad2010-04-23 23:31:47 +000017import gc
Thomas Woutersed03b412007-08-28 21:37:11 +000018import os
Antoine Pitroucfcd8ad2010-04-23 23:31:47 +000019import errno
Thomas Woutersed03b412007-08-28 21:37:11 +000020import pprint
Antoine Pitrou803e6d62010-10-13 10:36:15 +000021import urllib.request
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020022import threading
Thomas Woutersed03b412007-08-28 21:37:11 +000023import traceback
Bill Janssen54cc54c2007-12-14 22:08:56 +000024import asyncore
Antoine Pitrou9d543662010-04-23 23:10:32 +000025import weakref
Antoine Pitrou15cee622010-08-04 16:45:21 +000026import platform
Christian Heimes892d66e2018-01-29 14:10:18 +010027import sysconfig
Christian Heimesdf6ac7e2019-09-26 17:02:59 +020028import functools
Christian Heimes888bbdc2017-09-07 14:18:21 -070029try:
30 import ctypes
31except ImportError:
32 ctypes = None
Thomas Woutersed03b412007-08-28 21:37:11 +000033
Hai Shia7f5d932020-08-04 00:41:24 +080034ssl = import_helper.import_module("ssl")
Christian Heimes666991f2021-04-26 15:01:40 +020035import _ssl
Antoine Pitrou05d936d2010-10-13 11:38:36 +000036
Ethan Furmana02cb472021-04-21 10:20:44 -070037from ssl import TLSVersion, _TLSContentType, _TLSMessageType, _TLSAlertType
Martin Panter3840b2a2016-03-27 01:53:46 +000038
Paul Monsonf3550692019-06-19 13:09:54 -070039Py_DEBUG = hasattr(sys, 'gettotalrefcount')
40Py_DEBUG_WIN32 = Py_DEBUG and sys.platform == 'win32'
41
Antoine Pitrou2463e5f2013-03-28 22:24:43 +010042PROTOCOLS = sorted(ssl._PROTOCOL_NAMES)
Serhiy Storchaka16994912020-04-25 10:06:29 +030043HOST = socket_helper.HOST
Christian Heimesd37b74f2021-04-19 08:31:29 +020044IS_OPENSSL_3_0_0 = ssl.OPENSSL_VERSION_INFO >= (3, 0, 0)
Christian Heimes892d66e2018-01-29 14:10:18 +010045PY_SSL_DEFAULT_CIPHERS = sysconfig.get_config_var('PY_SSL_DEFAULT_CIPHERS')
Antoine Pitrou152efa22010-05-16 18:19:27 +000046
Victor Stinner3ef63442019-02-19 18:06:03 +010047PROTOCOL_TO_TLS_VERSION = {}
48for proto, ver in (
49 ("PROTOCOL_SSLv23", "SSLv3"),
50 ("PROTOCOL_TLSv1", "TLSv1"),
51 ("PROTOCOL_TLSv1_1", "TLSv1_1"),
52):
53 try:
54 proto = getattr(ssl, proto)
55 ver = getattr(ssl.TLSVersion, ver)
56 except AttributeError:
57 continue
58 PROTOCOL_TO_TLS_VERSION[proto] = ver
59
Christian Heimesefff7062013-11-21 03:35:02 +010060def data_file(*name):
61 return os.path.join(os.path.dirname(__file__), *name)
Antoine Pitrou152efa22010-05-16 18:19:27 +000062
Antoine Pitrou81564092010-10-08 23:06:24 +000063# The custom key and certificate files used in test_ssl are generated
64# using Lib/test/make_ssl_certs.py.
65# Other certificates are simply fetched from the Internet servers they
66# are meant to authenticate.
67
Antoine Pitrou152efa22010-05-16 18:19:27 +000068CERTFILE = data_file("keycert.pem")
Victor Stinner313a1202010-06-11 23:56:51 +000069BYTES_CERTFILE = os.fsencode(CERTFILE)
Antoine Pitrou152efa22010-05-16 18:19:27 +000070ONLYCERT = data_file("ssl_cert.pem")
71ONLYKEY = data_file("ssl_key.pem")
Victor Stinner313a1202010-06-11 23:56:51 +000072BYTES_ONLYCERT = os.fsencode(ONLYCERT)
73BYTES_ONLYKEY = os.fsencode(ONLYKEY)
Antoine Pitrou4fd1e6a2011-08-25 14:39:44 +020074CERTFILE_PROTECTED = data_file("keycert.passwd.pem")
75ONLYKEY_PROTECTED = data_file("ssl_key.passwd.pem")
76KEY_PASSWORD = "somepass"
Antoine Pitrou152efa22010-05-16 18:19:27 +000077CAPATH = data_file("capath")
Victor Stinner313a1202010-06-11 23:56:51 +000078BYTES_CAPATH = os.fsencode(CAPATH)
Christian Heimesefff7062013-11-21 03:35:02 +010079CAFILE_NEURONIO = data_file("capath", "4e1295a3.0")
80CAFILE_CACERT = data_file("capath", "5ed36f99.0")
81
Christian Heimesbd5c7d22018-01-20 15:16:30 +010082CERTFILE_INFO = {
83 'issuer': ((('countryName', 'XY'),),
84 (('localityName', 'Castle Anthrax'),),
85 (('organizationName', 'Python Software Foundation'),),
86 (('commonName', 'localhost'),)),
Christian Heimese6dac002018-08-30 07:25:49 +020087 'notAfter': 'Aug 26 14:23:15 2028 GMT',
88 'notBefore': 'Aug 29 14:23:15 2018 GMT',
89 'serialNumber': '98A7CF88C74A32ED',
Christian Heimesbd5c7d22018-01-20 15:16:30 +010090 'subject': ((('countryName', 'XY'),),
91 (('localityName', 'Castle Anthrax'),),
92 (('organizationName', 'Python Software Foundation'),),
93 (('commonName', 'localhost'),)),
94 'subjectAltName': (('DNS', 'localhost'),),
95 'version': 3
96}
Antoine Pitrou152efa22010-05-16 18:19:27 +000097
Christian Heimes22587792013-11-21 23:56:13 +010098# empty CRL
99CRLFILE = data_file("revocation.crl")
100
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100101# Two keys and certs signed by the same CA (for SNI tests)
102SIGNED_CERTFILE = data_file("keycert3.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +0200103SIGNED_CERTFILE_HOSTNAME = 'localhost'
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100104
105SIGNED_CERTFILE_INFO = {
106 'OCSP': ('http://testca.pythontest.net/testca/ocsp/',),
107 'caIssuers': ('http://testca.pythontest.net/testca/pycacert.cer',),
108 'crlDistributionPoints': ('http://testca.pythontest.net/testca/revocation.crl',),
109 'issuer': ((('countryName', 'XY'),),
110 (('organizationName', 'Python Software Foundation CA'),),
111 (('commonName', 'our-ca-server'),)),
Christian Heimesb467d9a2021-04-17 10:07:19 +0200112 'notAfter': 'Oct 28 14:23:16 2037 GMT',
Christian Heimese6dac002018-08-30 07:25:49 +0200113 'notBefore': 'Aug 29 14:23:16 2018 GMT',
114 'serialNumber': 'CB2D80995A69525C',
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100115 'subject': ((('countryName', 'XY'),),
116 (('localityName', 'Castle Anthrax'),),
117 (('organizationName', 'Python Software Foundation'),),
118 (('commonName', 'localhost'),)),
119 'subjectAltName': (('DNS', 'localhost'),),
120 'version': 3
121}
122
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100123SIGNED_CERTFILE2 = data_file("keycert4.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +0200124SIGNED_CERTFILE2_HOSTNAME = 'fakehostname'
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100125SIGNED_CERTFILE_ECC = data_file("keycertecc.pem")
126SIGNED_CERTFILE_ECC_HOSTNAME = 'localhost-ecc'
127
Martin Panter3840b2a2016-03-27 01:53:46 +0000128# Same certificate as pycacert.pem, but without extra text in file
129SIGNING_CA = data_file("capath", "ceff1710.0")
Christian Heimes1c03abd2016-09-06 23:25:35 +0200130# cert with all kinds of subject alt names
131ALLSANFILE = data_file("allsans.pem")
Christian Heimes66e57422018-01-29 14:25:13 +0100132IDNSANSFILE = data_file("idnsans.pem")
Christian Heimesb467d9a2021-04-17 10:07:19 +0200133NOSANFILE = data_file("nosan.pem")
134NOSAN_HOSTNAME = 'localhost'
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100135
Martin Panter3d81d932016-01-14 09:36:00 +0000136REMOTE_HOST = "self-signed.pythontest.net"
Antoine Pitrou152efa22010-05-16 18:19:27 +0000137
138EMPTYCERT = data_file("nullcert.pem")
139BADCERT = data_file("badcert.pem")
Martin Panter407b62f2016-01-30 03:41:43 +0000140NONEXISTINGCERT = data_file("XXXnonexisting.pem")
Antoine Pitrou152efa22010-05-16 18:19:27 +0000141BADKEY = data_file("badkey.pem")
Antoine Pitroud8c347a2011-10-01 19:20:25 +0200142NOKIACERT = data_file("nokia.pem")
Christian Heimes824f7f32013-08-17 00:54:47 +0200143NULLBYTECERT = data_file("nullbytecert.pem")
Christian Heimesa37f5242019-01-15 23:47:42 +0100144TALOS_INVALID_CRLDP = data_file("talos-2019-0758.pem")
Antoine Pitrou152efa22010-05-16 18:19:27 +0000145
Christian Heimes88bfd0b2018-08-14 12:54:19 +0200146DHFILE = data_file("ffdh3072.pem")
Antoine Pitrou0e576f12011-12-22 10:03:38 +0100147BYTES_DHFILE = os.fsencode(DHFILE)
Thomas Woutersed03b412007-08-28 21:37:11 +0000148
Christian Heimes358cfd42016-09-10 22:43:48 +0200149# Not defined in all versions of OpenSSL
150OP_NO_COMPRESSION = getattr(ssl, "OP_NO_COMPRESSION", 0)
151OP_SINGLE_DH_USE = getattr(ssl, "OP_SINGLE_DH_USE", 0)
152OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0)
153OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0)
Christian Heimes05d9fe32018-02-27 08:55:39 +0100154OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0)
Christian Heimes6f37ebc2021-04-09 17:59:21 +0200155OP_IGNORE_UNEXPECTED_EOF = getattr(ssl, "OP_IGNORE_UNEXPECTED_EOF", 0)
Christian Heimes358cfd42016-09-10 22:43:48 +0200156
Christian Heimesf6c6b582021-03-18 23:06:50 +0100157# Ubuntu has patched OpenSSL and changed behavior of security level 2
158# see https://bugs.python.org/issue41561#msg389003
159def is_ubuntu():
160 try:
161 # Assume that any references of "ubuntu" implies Ubuntu-like distro
162 # The workaround is not required for 18.04, but doesn't hurt either.
163 with open("/etc/os-release", encoding="utf-8") as f:
164 return "ubuntu" in f.read()
165 except FileNotFoundError:
166 return False
167
168if is_ubuntu():
169 def seclevel_workaround(*ctxs):
170 """"Lower security level to '1' and allow all ciphers for TLS 1.0/1"""
171 for ctx in ctxs:
Christian Heimes34477502021-04-12 12:00:38 +0200172 if (
173 hasattr(ctx, "minimum_version") and
174 ctx.minimum_version <= ssl.TLSVersion.TLSv1_1
175 ):
Christian Heimesf6c6b582021-03-18 23:06:50 +0100176 ctx.set_ciphers("@SECLEVEL=1:ALL")
177else:
178 def seclevel_workaround(*ctxs):
179 pass
180
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100181
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200182def has_tls_protocol(protocol):
183 """Check if a TLS protocol is available and enabled
184
185 :param protocol: enum ssl._SSLMethod member or name
186 :return: bool
187 """
188 if isinstance(protocol, str):
189 assert protocol.startswith('PROTOCOL_')
190 protocol = getattr(ssl, protocol, None)
191 if protocol is None:
192 return False
193 if protocol in {
194 ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS_SERVER,
195 ssl.PROTOCOL_TLS_CLIENT
196 }:
197 # auto-negotiate protocols are always available
198 return True
199 name = protocol.name
200 return has_tls_version(name[len('PROTOCOL_'):])
201
202
203@functools.lru_cache
204def has_tls_version(version):
205 """Check if a TLS/SSL version is enabled
206
207 :param version: TLS version name or ssl.TLSVersion member
208 :return: bool
209 """
210 if version == "SSLv2":
211 # never supported and not even in TLSVersion enum
212 return False
213
214 if isinstance(version, str):
215 version = ssl.TLSVersion.__members__[version]
216
217 # check compile time flags like ssl.HAS_TLSv1_2
218 if not getattr(ssl, f'HAS_{version.name}'):
219 return False
220
Christian Heimes5151d642021-04-09 15:43:06 +0200221 if IS_OPENSSL_3_0_0 and version < ssl.TLSVersion.TLSv1_2:
222 # bpo43791: 3.0.0-alpha14 fails with TLSV1_ALERT_INTERNAL_ERROR
223 return False
224
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200225 # check runtime and dynamic crypto policy settings. A TLS version may
226 # be compiled in but disabled by a policy or config option.
Christian Heimes2875c602021-04-19 07:27:10 +0200227 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200228 if (
Christian Heimes9f772682019-09-26 18:23:17 +0200229 hasattr(ctx, 'minimum_version') and
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200230 ctx.minimum_version != ssl.TLSVersion.MINIMUM_SUPPORTED and
231 version < ctx.minimum_version
232 ):
233 return False
234 if (
Christian Heimes9f772682019-09-26 18:23:17 +0200235 hasattr(ctx, 'maximum_version') and
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200236 ctx.maximum_version != ssl.TLSVersion.MAXIMUM_SUPPORTED and
237 version > ctx.maximum_version
238 ):
239 return False
240
241 return True
242
243
244def requires_tls_version(version):
245 """Decorator to skip tests when a required TLS version is not available
246
247 :param version: TLS version name or ssl.TLSVersion member
248 :return:
249 """
250 def decorator(func):
251 @functools.wraps(func)
252 def wrapper(*args, **kw):
253 if not has_tls_version(version):
254 raise unittest.SkipTest(f"{version} is not available.")
255 else:
256 return func(*args, **kw)
257 return wrapper
258 return decorator
259
260
Thomas Woutersed03b412007-08-28 21:37:11 +0000261def handle_error(prefix):
262 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000263 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000264 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +0000265
Christian Heimesb7b92252018-02-25 09:49:31 +0100266
Antoine Pitrouc695c952014-04-28 20:57:36 +0200267def utc_offset(): #NOTE: ignore issues like #1647654
268 # local time = utc time + utc offset
269 if time.daylight and time.localtime().tm_isdst > 0:
270 return -time.altzone # seconds
271 return -time.timezone
272
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100273
Christian Heimes2875c602021-04-19 07:27:10 +0200274ignore_deprecation = warnings_helper.ignore_warnings(
275 category=DeprecationWarning
276)
Antoine Pitrou23df4832010-08-04 17:14:06 +0000277
Christian Heimes2875c602021-04-19 07:27:10 +0200278
279def test_wrap_socket(sock, *,
Christian Heimesd0486372016-09-10 23:23:33 +0200280 cert_reqs=ssl.CERT_NONE, ca_certs=None,
281 ciphers=None, certfile=None, keyfile=None,
282 **kwargs):
Christian Heimes2875c602021-04-19 07:27:10 +0200283 if not kwargs.get("server_side"):
284 kwargs["server_hostname"] = SIGNED_CERTFILE_HOSTNAME
285 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
286 else:
287 context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimesd0486372016-09-10 23:23:33 +0200288 if cert_reqs is not None:
Christian Heimesa170fa12017-09-15 20:27:30 +0200289 if cert_reqs == ssl.CERT_NONE:
290 context.check_hostname = False
Christian Heimesd0486372016-09-10 23:23:33 +0200291 context.verify_mode = cert_reqs
292 if ca_certs is not None:
293 context.load_verify_locations(ca_certs)
294 if certfile is not None or keyfile is not None:
295 context.load_cert_chain(certfile, keyfile)
296 if ciphers is not None:
297 context.set_ciphers(ciphers)
298 return context.wrap_socket(sock, **kwargs)
299
Christian Heimesa170fa12017-09-15 20:27:30 +0200300
Christian Heimes666991f2021-04-26 15:01:40 +0200301def testing_context(server_cert=SIGNED_CERTFILE, *, server_chain=True):
Christian Heimesa170fa12017-09-15 20:27:30 +0200302 """Create context
303
304 client_context, server_context, hostname = testing_context()
305 """
306 if server_cert == SIGNED_CERTFILE:
307 hostname = SIGNED_CERTFILE_HOSTNAME
308 elif server_cert == SIGNED_CERTFILE2:
309 hostname = SIGNED_CERTFILE2_HOSTNAME
Christian Heimesb467d9a2021-04-17 10:07:19 +0200310 elif server_cert == NOSANFILE:
311 hostname = NOSAN_HOSTNAME
Christian Heimesa170fa12017-09-15 20:27:30 +0200312 else:
313 raise ValueError(server_cert)
314
315 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
316 client_context.load_verify_locations(SIGNING_CA)
317
318 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
319 server_context.load_cert_chain(server_cert)
Christian Heimes666991f2021-04-26 15:01:40 +0200320 if server_chain:
321 server_context.load_verify_locations(SIGNING_CA)
Christian Heimesa170fa12017-09-15 20:27:30 +0200322
323 return client_context, server_context, hostname
324
325
Antoine Pitrou152efa22010-05-16 18:19:27 +0000326class BasicSocketTests(unittest.TestCase):
Thomas Woutersed03b412007-08-28 21:37:11 +0000327
Antoine Pitrou480a1242010-04-28 21:37:09 +0000328 def test_constants(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000329 ssl.CERT_NONE
330 ssl.CERT_OPTIONAL
331 ssl.CERT_REQUIRED
Antoine Pitrou6db49442011-12-19 13:27:11 +0100332 ssl.OP_CIPHER_SERVER_PREFERENCE
Antoine Pitrou0e576f12011-12-22 10:03:38 +0100333 ssl.OP_SINGLE_DH_USE
Christian Heimesd37b74f2021-04-19 08:31:29 +0200334 ssl.OP_SINGLE_ECDH_USE
Christian Heimes39258d32021-04-17 11:36:35 +0200335 ssl.OP_NO_COMPRESSION
Christian Heimesd37b74f2021-04-19 08:31:29 +0200336 self.assertEqual(ssl.HAS_SNI, True)
337 self.assertEqual(ssl.HAS_ECDH, True)
338 self.assertEqual(ssl.HAS_TLSv1_2, True)
339 self.assertEqual(ssl.HAS_TLSv1_3, True)
Christian Heimescb5b68a2017-09-07 18:07:00 -0700340 ssl.OP_NO_SSLv2
341 ssl.OP_NO_SSLv3
342 ssl.OP_NO_TLSv1
343 ssl.OP_NO_TLSv1_3
Christian Heimes39258d32021-04-17 11:36:35 +0200344 ssl.OP_NO_TLSv1_1
345 ssl.OP_NO_TLSv1_2
Christian Heimesa170fa12017-09-15 20:27:30 +0200346 self.assertEqual(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv23)
Thomas Woutersed03b412007-08-28 21:37:11 +0000347
Christian Heimes91554e42021-05-02 09:47:45 +0200348 def test_ssl_types(self):
349 ssl_types = [
350 _ssl._SSLContext,
351 _ssl._SSLSocket,
352 _ssl.MemoryBIO,
353 _ssl.Certificate,
354 _ssl.SSLSession,
355 _ssl.SSLError,
356 ]
357 for ssl_type in ssl_types:
358 with self.subTest(ssl_type=ssl_type):
359 with self.assertRaisesRegex(TypeError, "immutable type"):
360 ssl_type.value = None
361 with self.assertRaisesRegex(
362 TypeError,
363 "cannot create '_ssl.Certificate' instances"
364 ):
365 _ssl.Certificate()
366
Christian Heimes9d50ab52018-02-27 10:17:30 +0100367 def test_private_init(self):
368 with self.assertRaisesRegex(TypeError, "public constructor"):
369 with socket.socket() as s:
370 ssl.SSLSocket(s)
371
Antoine Pitrou172f0252014-04-18 20:33:08 +0200372 def test_str_for_enums(self):
373 # Make sure that the PROTOCOL_* constants have enum-like string
374 # reprs.
Christian Heimes2875c602021-04-19 07:27:10 +0200375 proto = ssl.PROTOCOL_TLS_CLIENT
376 self.assertEqual(str(proto), 'PROTOCOL_TLS_CLIENT')
Antoine Pitrou172f0252014-04-18 20:33:08 +0200377 ctx = ssl.SSLContext(proto)
378 self.assertIs(ctx.protocol, proto)
379
Antoine Pitrou480a1242010-04-28 21:37:09 +0000380 def test_random(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000381 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000382 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000383 sys.stdout.write("\n RAND_status is %d (%s)\n"
384 % (v, (v and "sufficient randomness") or
385 "insufficient randomness"))
Victor Stinner99c8b162011-05-24 12:05:19 +0200386
Christian Heimes2875c602021-04-19 07:27:10 +0200387 with warnings_helper.check_warnings():
388 data, is_cryptographic = ssl.RAND_pseudo_bytes(16)
Victor Stinner99c8b162011-05-24 12:05:19 +0200389 self.assertEqual(len(data), 16)
390 self.assertEqual(is_cryptographic, v == 1)
391 if v:
392 data = ssl.RAND_bytes(16)
393 self.assertEqual(len(data), 16)
Victor Stinner2e2baa92011-05-25 11:15:16 +0200394 else:
395 self.assertRaises(ssl.SSLError, ssl.RAND_bytes, 16)
Victor Stinner99c8b162011-05-24 12:05:19 +0200396
Victor Stinner1e81a392013-12-19 16:47:04 +0100397 # negative num is invalid
398 self.assertRaises(ValueError, ssl.RAND_bytes, -5)
Christian Heimes2875c602021-04-19 07:27:10 +0200399 with warnings_helper.check_warnings():
400 self.assertRaises(ValueError, ssl.RAND_pseudo_bytes, -5)
Victor Stinner1e81a392013-12-19 16:47:04 +0100401
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000402 ssl.RAND_add("this is a random string", 75.0)
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200403 ssl.RAND_add(b"this is a random bytes object", 75.0)
404 ssl.RAND_add(bytearray(b"this is a random bytearray object"), 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +0000405
Antoine Pitrou480a1242010-04-28 21:37:09 +0000406 def test_parse_cert(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000407 # note that this uses an 'unofficial' function in _ssl.c,
408 # provided solely for this test, to exercise the certificate
409 # parsing code
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100410 self.assertEqual(
411 ssl._ssl._test_decode_cert(CERTFILE),
412 CERTFILE_INFO
413 )
414 self.assertEqual(
415 ssl._ssl._test_decode_cert(SIGNED_CERTFILE),
416 SIGNED_CERTFILE_INFO
417 )
418
Antoine Pitroud8c347a2011-10-01 19:20:25 +0200419 # Issue #13034: the subjectAltName in some certificates
420 # (notably projects.developer.nokia.com:443) wasn't parsed
421 p = ssl._ssl._test_decode_cert(NOKIACERT)
422 if support.verbose:
423 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
424 self.assertEqual(p['subjectAltName'],
425 (('DNS', 'projects.developer.nokia.com'),
426 ('DNS', 'projects.forum.nokia.com'))
427 )
Christian Heimesbd3a7f92013-11-21 03:40:15 +0100428 # extra OCSP and AIA fields
429 self.assertEqual(p['OCSP'], ('http://ocsp.verisign.com',))
430 self.assertEqual(p['caIssuers'],
431 ('http://SVRIntl-G3-aia.verisign.com/SVRIntlG3.cer',))
432 self.assertEqual(p['crlDistributionPoints'],
433 ('http://SVRIntl-G3-crl.verisign.com/SVRIntlG3.crl',))
Thomas Woutersed03b412007-08-28 21:37:11 +0000434
Christian Heimesa37f5242019-01-15 23:47:42 +0100435 def test_parse_cert_CVE_2019_5010(self):
436 p = ssl._ssl._test_decode_cert(TALOS_INVALID_CRLDP)
437 if support.verbose:
438 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
439 self.assertEqual(
440 p,
441 {
442 'issuer': (
443 (('countryName', 'UK'),), (('commonName', 'cody-ca'),)),
444 'notAfter': 'Jun 14 18:00:58 2028 GMT',
445 'notBefore': 'Jun 18 18:00:58 2018 GMT',
446 'serialNumber': '02',
447 'subject': ((('countryName', 'UK'),),
448 (('commonName',
449 'codenomicon-vm-2.test.lal.cisco.com'),)),
450 'subjectAltName': (
451 ('DNS', 'codenomicon-vm-2.test.lal.cisco.com'),),
452 'version': 3
453 }
454 )
455
Christian Heimes824f7f32013-08-17 00:54:47 +0200456 def test_parse_cert_CVE_2013_4238(self):
457 p = ssl._ssl._test_decode_cert(NULLBYTECERT)
458 if support.verbose:
459 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
460 subject = ((('countryName', 'US'),),
461 (('stateOrProvinceName', 'Oregon'),),
462 (('localityName', 'Beaverton'),),
463 (('organizationName', 'Python Software Foundation'),),
464 (('organizationalUnitName', 'Python Core Development'),),
465 (('commonName', 'null.python.org\x00example.org'),),
466 (('emailAddress', 'python-dev@python.org'),))
467 self.assertEqual(p['subject'], subject)
468 self.assertEqual(p['issuer'], subject)
Christian Heimes157c9832013-08-25 14:12:41 +0200469 if ssl._OPENSSL_API_VERSION >= (0, 9, 8):
470 san = (('DNS', 'altnull.python.org\x00example.com'),
471 ('email', 'null@python.org\x00user@example.org'),
472 ('URI', 'http://null.python.org\x00http://example.org'),
473 ('IP Address', '192.0.2.1'),
Christian Heimes2b7de662019-12-07 17:59:36 +0100474 ('IP Address', '2001:DB8:0:0:0:0:0:1'))
Christian Heimes157c9832013-08-25 14:12:41 +0200475 else:
476 # OpenSSL 0.9.7 doesn't support IPv6 addresses in subjectAltName
477 san = (('DNS', 'altnull.python.org\x00example.com'),
478 ('email', 'null@python.org\x00user@example.org'),
479 ('URI', 'http://null.python.org\x00http://example.org'),
480 ('IP Address', '192.0.2.1'),
481 ('IP Address', '<invalid>'))
482
483 self.assertEqual(p['subjectAltName'], san)
Christian Heimes824f7f32013-08-17 00:54:47 +0200484
Christian Heimes1c03abd2016-09-06 23:25:35 +0200485 def test_parse_all_sans(self):
486 p = ssl._ssl._test_decode_cert(ALLSANFILE)
487 self.assertEqual(p['subjectAltName'],
488 (
489 ('DNS', 'allsans'),
490 ('othername', '<unsupported>'),
491 ('othername', '<unsupported>'),
492 ('email', 'user@example.org'),
493 ('DNS', 'www.example.org'),
494 ('DirName',
495 ((('countryName', 'XY'),),
496 (('localityName', 'Castle Anthrax'),),
497 (('organizationName', 'Python Software Foundation'),),
498 (('commonName', 'dirname example'),))),
499 ('URI', 'https://www.python.org/'),
500 ('IP Address', '127.0.0.1'),
Christian Heimes2b7de662019-12-07 17:59:36 +0100501 ('IP Address', '0:0:0:0:0:0:0:1'),
Christian Heimes1c03abd2016-09-06 23:25:35 +0200502 ('Registered ID', '1.2.3.4.5')
503 )
504 )
505
Antoine Pitrou480a1242010-04-28 21:37:09 +0000506 def test_DER_to_PEM(self):
Martin Panter3d81d932016-01-14 09:36:00 +0000507 with open(CAFILE_CACERT, 'r') as f:
Antoine Pitrou480a1242010-04-28 21:37:09 +0000508 pem = f.read()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000509 d1 = ssl.PEM_cert_to_DER_cert(pem)
510 p2 = ssl.DER_cert_to_PEM_cert(d1)
511 d2 = ssl.PEM_cert_to_DER_cert(p2)
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000512 self.assertEqual(d1, d2)
Antoine Pitrou9bfbe612010-04-27 22:08:08 +0000513 if not p2.startswith(ssl.PEM_HEADER + '\n'):
514 self.fail("DER-to-PEM didn't include correct header:\n%r\n" % p2)
515 if not p2.endswith('\n' + ssl.PEM_FOOTER + '\n'):
516 self.fail("DER-to-PEM didn't include correct footer:\n%r\n" % p2)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000517
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000518 def test_openssl_version(self):
519 n = ssl.OPENSSL_VERSION_NUMBER
520 t = ssl.OPENSSL_VERSION_INFO
521 s = ssl.OPENSSL_VERSION
522 self.assertIsInstance(n, int)
523 self.assertIsInstance(t, tuple)
524 self.assertIsInstance(s, str)
525 # Some sanity checks follow
Christian Heimesd37b74f2021-04-19 08:31:29 +0200526 # >= 1.1.1
527 self.assertGreaterEqual(n, 0x10101000)
Christian Heimes2b7de662019-12-07 17:59:36 +0100528 # < 4.0
529 self.assertLess(n, 0x40000000)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000530 major, minor, fix, patch, status = t
Christian Heimes2b7de662019-12-07 17:59:36 +0100531 self.assertGreaterEqual(major, 1)
532 self.assertLess(major, 4)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000533 self.assertGreaterEqual(minor, 0)
534 self.assertLess(minor, 256)
535 self.assertGreaterEqual(fix, 0)
536 self.assertLess(fix, 256)
537 self.assertGreaterEqual(patch, 0)
Ned Deily05784a72015-02-05 17:20:13 +1100538 self.assertLessEqual(patch, 63)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000539 self.assertGreaterEqual(status, 0)
540 self.assertLessEqual(status, 15)
Christian Heimesd37b74f2021-04-19 08:31:29 +0200541
542 libressl_ver = f"LibreSSL {major:d}"
543 openssl_ver = f"OpenSSL {major:d}.{minor:d}.{fix:d}"
544 self.assertTrue(
545 s.startswith((openssl_ver, libressl_ver)),
546 (s, t, hex(n))
547 )
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000548
Antoine Pitrou9d543662010-04-23 23:10:32 +0000549 @support.cpython_only
550 def test_refcycle(self):
551 # Issue #7943: an SSL object doesn't create reference cycles with
552 # itself.
553 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200554 ss = test_wrap_socket(s)
Antoine Pitrou9d543662010-04-23 23:10:32 +0000555 wr = weakref.ref(ss)
Hai Shia7f5d932020-08-04 00:41:24 +0800556 with warnings_helper.check_warnings(("", ResourceWarning)):
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100557 del ss
Victor Stinnere0b75b72016-03-21 17:26:04 +0100558 self.assertEqual(wr(), None)
Antoine Pitrou9d543662010-04-23 23:10:32 +0000559
Antoine Pitroua468adc2010-09-14 14:43:44 +0000560 def test_wrapped_unconnected(self):
561 # Methods on an unconnected SSLSocket propagate the original
Andrew Svetlov0832af62012-12-18 23:10:48 +0200562 # OSError raise by the underlying socket object.
Antoine Pitroua468adc2010-09-14 14:43:44 +0000563 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200564 with test_wrap_socket(s) as ss:
Antoine Pitroue9bb4732013-01-12 21:56:56 +0100565 self.assertRaises(OSError, ss.recv, 1)
566 self.assertRaises(OSError, ss.recv_into, bytearray(b'x'))
567 self.assertRaises(OSError, ss.recvfrom, 1)
568 self.assertRaises(OSError, ss.recvfrom_into, bytearray(b'x'), 1)
569 self.assertRaises(OSError, ss.send, b'x')
570 self.assertRaises(OSError, ss.sendto, b'x', ('0.0.0.0', 0))
Serhiy Storchaka42b1d612018-12-06 22:36:55 +0200571 self.assertRaises(NotImplementedError, ss.dup)
Christian Heimes141c5e82018-02-24 21:10:57 +0100572 self.assertRaises(NotImplementedError, ss.sendmsg,
573 [b'x'], (), 0, ('0.0.0.0', 0))
Serhiy Storchaka42b1d612018-12-06 22:36:55 +0200574 self.assertRaises(NotImplementedError, ss.recvmsg, 100)
575 self.assertRaises(NotImplementedError, ss.recvmsg_into,
576 [bytearray(100)])
Antoine Pitroua468adc2010-09-14 14:43:44 +0000577
Antoine Pitrou40f08742010-04-24 22:04:40 +0000578 def test_timeout(self):
579 # Issue #8524: when creating an SSL socket, the timeout of the
580 # original socket should be retained.
581 for timeout in (None, 0.0, 5.0):
582 s = socket.socket(socket.AF_INET)
583 s.settimeout(timeout)
Christian Heimesd0486372016-09-10 23:23:33 +0200584 with test_wrap_socket(s) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100585 self.assertEqual(timeout, ss.gettimeout())
Antoine Pitrou40f08742010-04-24 22:04:40 +0000586
Christian Heimes2875c602021-04-19 07:27:10 +0200587 @ignore_deprecation
Christian Heimesd0486372016-09-10 23:23:33 +0200588 def test_errors_sslwrap(self):
Giampaolo Rodolà745ab382010-08-29 19:25:49 +0000589 sock = socket.socket()
Ezio Melottied3a7d22010-12-01 02:32:32 +0000590 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000591 "certfile must be specified",
592 ssl.wrap_socket, sock, keyfile=CERTFILE)
Ezio Melottied3a7d22010-12-01 02:32:32 +0000593 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000594 "certfile must be specified for server-side operations",
595 ssl.wrap_socket, sock, server_side=True)
Ezio Melottied3a7d22010-12-01 02:32:32 +0000596 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000597 "certfile must be specified for server-side operations",
Christian Heimesd0486372016-09-10 23:23:33 +0200598 ssl.wrap_socket, sock, server_side=True, certfile="")
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100599 with ssl.wrap_socket(sock, server_side=True, certfile=CERTFILE) as s:
600 self.assertRaisesRegex(ValueError, "can't connect in server-side mode",
Christian Heimesd0486372016-09-10 23:23:33 +0200601 s.connect, (HOST, 8080))
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200602 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000603 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000604 ssl.wrap_socket(sock, certfile=NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +0000605 self.assertEqual(cm.exception.errno, errno.ENOENT)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200606 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000607 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000608 ssl.wrap_socket(sock,
609 certfile=CERTFILE, keyfile=NONEXISTINGCERT)
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000610 self.assertEqual(cm.exception.errno, errno.ENOENT)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200611 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000612 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000613 ssl.wrap_socket(sock,
614 certfile=NONEXISTINGCERT, keyfile=NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +0000615 self.assertEqual(cm.exception.errno, errno.ENOENT)
Giampaolo Rodolà745ab382010-08-29 19:25:49 +0000616
Martin Panter3464ea22016-02-01 21:58:11 +0000617 def bad_cert_test(self, certfile):
618 """Check that trying to use the given client certificate fails"""
619 certfile = os.path.join(os.path.dirname(__file__) or os.curdir,
620 certfile)
621 sock = socket.socket()
622 self.addCleanup(sock.close)
623 with self.assertRaises(ssl.SSLError):
Christian Heimesd0486372016-09-10 23:23:33 +0200624 test_wrap_socket(sock,
Christian Heimesa170fa12017-09-15 20:27:30 +0200625 certfile=certfile)
Martin Panter3464ea22016-02-01 21:58:11 +0000626
627 def test_empty_cert(self):
628 """Wrapping with an empty cert file"""
629 self.bad_cert_test("nullcert.pem")
630
631 def test_malformed_cert(self):
632 """Wrapping with a badly formatted certificate (syntax error)"""
633 self.bad_cert_test("badcert.pem")
634
635 def test_malformed_key(self):
636 """Wrapping with a badly formatted key (syntax error)"""
637 self.bad_cert_test("badkey.pem")
638
Christian Heimes2875c602021-04-19 07:27:10 +0200639 @ignore_deprecation
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000640 def test_match_hostname(self):
641 def ok(cert, hostname):
642 ssl.match_hostname(cert, hostname)
643 def fail(cert, hostname):
644 self.assertRaises(ssl.CertificateError,
645 ssl.match_hostname, cert, hostname)
646
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100647 # -- Hostname matching --
648
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000649 cert = {'subject': ((('commonName', 'example.com'),),)}
650 ok(cert, 'example.com')
651 ok(cert, 'ExAmple.cOm')
652 fail(cert, 'www.example.com')
653 fail(cert, '.example.com')
654 fail(cert, 'example.org')
655 fail(cert, 'exampleXcom')
656
657 cert = {'subject': ((('commonName', '*.a.com'),),)}
658 ok(cert, 'foo.a.com')
659 fail(cert, 'bar.foo.a.com')
660 fail(cert, 'a.com')
661 fail(cert, 'Xa.com')
662 fail(cert, '.a.com')
663
Mandeep Singhede2ac92017-11-27 04:01:27 +0530664 # only match wildcards when they are the only thing
665 # in left-most segment
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000666 cert = {'subject': ((('commonName', 'f*.com'),),)}
Mandeep Singhede2ac92017-11-27 04:01:27 +0530667 fail(cert, 'foo.com')
668 fail(cert, 'f.com')
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000669 fail(cert, 'bar.com')
670 fail(cert, 'foo.a.com')
671 fail(cert, 'bar.foo.com')
672
Christian Heimes824f7f32013-08-17 00:54:47 +0200673 # NULL bytes are bad, CVE-2013-4073
674 cert = {'subject': ((('commonName',
675 'null.python.org\x00example.org'),),)}
676 ok(cert, 'null.python.org\x00example.org') # or raise an error?
677 fail(cert, 'example.org')
678 fail(cert, 'null.python.org')
679
Georg Brandl72c98d32013-10-27 07:16:53 +0100680 # error cases with wildcards
681 cert = {'subject': ((('commonName', '*.*.a.com'),),)}
682 fail(cert, 'bar.foo.a.com')
683 fail(cert, 'a.com')
684 fail(cert, 'Xa.com')
685 fail(cert, '.a.com')
686
687 cert = {'subject': ((('commonName', 'a.*.com'),),)}
688 fail(cert, 'a.foo.com')
689 fail(cert, 'a..com')
690 fail(cert, 'a.com')
691
692 # wildcard doesn't match IDNA prefix 'xn--'
693 idna = 'püthon.python.org'.encode("idna").decode("ascii")
694 cert = {'subject': ((('commonName', idna),),)}
695 ok(cert, idna)
696 cert = {'subject': ((('commonName', 'x*.python.org'),),)}
697 fail(cert, idna)
698 cert = {'subject': ((('commonName', 'xn--p*.python.org'),),)}
699 fail(cert, idna)
700
701 # wildcard in first fragment and IDNA A-labels in sequent fragments
702 # are supported.
703 idna = 'www*.pythön.org'.encode("idna").decode("ascii")
704 cert = {'subject': ((('commonName', idna),),)}
Mandeep Singhede2ac92017-11-27 04:01:27 +0530705 fail(cert, 'www.pythön.org'.encode("idna").decode("ascii"))
706 fail(cert, 'www1.pythön.org'.encode("idna").decode("ascii"))
Georg Brandl72c98d32013-10-27 07:16:53 +0100707 fail(cert, 'ftp.pythön.org'.encode("idna").decode("ascii"))
708 fail(cert, 'pythön.org'.encode("idna").decode("ascii"))
709
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000710 # Slightly fake real-world example
711 cert = {'notAfter': 'Jun 26 21:41:46 2011 GMT',
712 'subject': ((('commonName', 'linuxfrz.org'),),),
713 'subjectAltName': (('DNS', 'linuxfr.org'),
714 ('DNS', 'linuxfr.com'),
715 ('othername', '<unsupported>'))}
716 ok(cert, 'linuxfr.org')
717 ok(cert, 'linuxfr.com')
718 # Not a "DNS" entry
719 fail(cert, '<unsupported>')
720 # When there is a subjectAltName, commonName isn't used
721 fail(cert, 'linuxfrz.org')
722
723 # A pristine real-world example
724 cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT',
725 'subject': ((('countryName', 'US'),),
726 (('stateOrProvinceName', 'California'),),
727 (('localityName', 'Mountain View'),),
728 (('organizationName', 'Google Inc'),),
729 (('commonName', 'mail.google.com'),))}
730 ok(cert, 'mail.google.com')
731 fail(cert, 'gmail.com')
732 # Only commonName is considered
733 fail(cert, 'California')
734
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100735 # -- IPv4 matching --
736 cert = {'subject': ((('commonName', 'example.com'),),),
737 'subjectAltName': (('DNS', 'example.com'),
738 ('IP Address', '10.11.12.13'),
Christian Heimes477b1b22019-07-02 20:39:42 +0200739 ('IP Address', '14.15.16.17'),
740 ('IP Address', '127.0.0.1'))}
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100741 ok(cert, '10.11.12.13')
742 ok(cert, '14.15.16.17')
Christian Heimes477b1b22019-07-02 20:39:42 +0200743 # socket.inet_ntoa(socket.inet_aton('127.1')) == '127.0.0.1'
744 fail(cert, '127.1')
745 fail(cert, '14.15.16.17 ')
746 fail(cert, '14.15.16.17 extra data')
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100747 fail(cert, '14.15.16.18')
748 fail(cert, 'example.net')
749
750 # -- IPv6 matching --
Serhiy Storchaka16994912020-04-25 10:06:29 +0300751 if socket_helper.IPV6_ENABLED:
Christian Heimesaef12832018-02-24 14:35:56 +0100752 cert = {'subject': ((('commonName', 'example.com'),),),
753 'subjectAltName': (
754 ('DNS', 'example.com'),
755 ('IP Address', '2001:0:0:0:0:0:0:CAFE\n'),
756 ('IP Address', '2003:0:0:0:0:0:0:BABA\n'))}
757 ok(cert, '2001::cafe')
758 ok(cert, '2003::baba')
Christian Heimes477b1b22019-07-02 20:39:42 +0200759 fail(cert, '2003::baba ')
760 fail(cert, '2003::baba extra data')
Christian Heimesaef12832018-02-24 14:35:56 +0100761 fail(cert, '2003::bebe')
762 fail(cert, 'example.net')
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100763
764 # -- Miscellaneous --
765
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000766 # Neither commonName nor subjectAltName
767 cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT',
768 'subject': ((('countryName', 'US'),),
769 (('stateOrProvinceName', 'California'),),
770 (('localityName', 'Mountain View'),),
771 (('organizationName', 'Google Inc'),))}
772 fail(cert, 'mail.google.com')
773
Antoine Pitrou1c86b442011-05-06 15:19:49 +0200774 # No DNS entry in subjectAltName but a commonName
775 cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT',
776 'subject': ((('countryName', 'US'),),
777 (('stateOrProvinceName', 'California'),),
778 (('localityName', 'Mountain View'),),
779 (('commonName', 'mail.google.com'),)),
780 'subjectAltName': (('othername', 'blabla'), )}
781 ok(cert, 'mail.google.com')
782
783 # No DNS entry subjectAltName and no commonName
784 cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT',
785 'subject': ((('countryName', 'US'),),
786 (('stateOrProvinceName', 'California'),),
787 (('localityName', 'Mountain View'),),
788 (('organizationName', 'Google Inc'),)),
789 'subjectAltName': (('othername', 'blabla'),)}
790 fail(cert, 'google.com')
791
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000792 # Empty cert / no cert
793 self.assertRaises(ValueError, ssl.match_hostname, None, 'example.com')
794 self.assertRaises(ValueError, ssl.match_hostname, {}, 'example.com')
795
Antoine Pitrou636f93c2013-05-18 17:56:42 +0200796 # Issue #17980: avoid denials of service by refusing more than one
797 # wildcard per fragment.
Christian Heimesaef12832018-02-24 14:35:56 +0100798 cert = {'subject': ((('commonName', 'a*b.example.com'),),)}
799 with self.assertRaisesRegex(
800 ssl.CertificateError,
801 "partial wildcards in leftmost label are not supported"):
802 ssl.match_hostname(cert, 'axxb.example.com')
803
804 cert = {'subject': ((('commonName', 'www.*.example.com'),),)}
805 with self.assertRaisesRegex(
806 ssl.CertificateError,
807 "wildcard can only be present in the leftmost label"):
808 ssl.match_hostname(cert, 'www.sub.example.com')
809
810 cert = {'subject': ((('commonName', 'a*b*.example.com'),),)}
811 with self.assertRaisesRegex(
812 ssl.CertificateError,
813 "too many wildcards"):
814 ssl.match_hostname(cert, 'axxbxxc.example.com')
815
816 cert = {'subject': ((('commonName', '*'),),)}
817 with self.assertRaisesRegex(
818 ssl.CertificateError,
819 "sole wildcard without additional labels are not support"):
820 ssl.match_hostname(cert, 'host')
821
822 cert = {'subject': ((('commonName', '*.com'),),)}
823 with self.assertRaisesRegex(
824 ssl.CertificateError,
825 r"hostname 'com' doesn't match '\*.com'"):
826 ssl.match_hostname(cert, 'com')
827
828 # extra checks for _inet_paton()
829 for invalid in ['1', '', '1.2.3', '256.0.0.1', '127.0.0.1/24']:
830 with self.assertRaises(ValueError):
831 ssl._inet_paton(invalid)
832 for ipaddr in ['127.0.0.1', '192.168.0.1']:
833 self.assertTrue(ssl._inet_paton(ipaddr))
Serhiy Storchaka16994912020-04-25 10:06:29 +0300834 if socket_helper.IPV6_ENABLED:
Christian Heimesaef12832018-02-24 14:35:56 +0100835 for ipaddr in ['::1', '2001:db8:85a3::8a2e:370:7334']:
836 self.assertTrue(ssl._inet_paton(ipaddr))
Antoine Pitrou636f93c2013-05-18 17:56:42 +0200837
Antoine Pitroud5323212010-10-22 18:19:07 +0000838 def test_server_side(self):
839 # server_hostname doesn't work for server sockets
Christian Heimesa170fa12017-09-15 20:27:30 +0200840 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroud2eca372010-10-29 23:41:37 +0000841 with socket.socket() as sock:
842 self.assertRaises(ValueError, ctx.wrap_socket, sock, True,
843 server_hostname="some.hostname")
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000844
Antoine Pitroud6494802011-07-21 01:11:30 +0200845 def test_unknown_channel_binding(self):
846 # should raise ValueError for unknown type
Giampaolo Rodolaeb7e29f2019-04-09 00:34:02 +0200847 s = socket.create_server(('127.0.0.1', 0))
Antoine Pitroub1fdf472014-10-05 20:41:53 +0200848 c = socket.socket(socket.AF_INET)
849 c.connect(s.getsockname())
Christian Heimesd0486372016-09-10 23:23:33 +0200850 with test_wrap_socket(c, do_handshake_on_connect=False) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100851 with self.assertRaises(ValueError):
852 ss.get_channel_binding("unknown-type")
Antoine Pitroub1fdf472014-10-05 20:41:53 +0200853 s.close()
Antoine Pitroud6494802011-07-21 01:11:30 +0200854
855 @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES,
856 "'tls-unique' channel binding not available")
857 def test_tls_unique_channel_binding(self):
858 # unconnected should return None for known type
859 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200860 with test_wrap_socket(s) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100861 self.assertIsNone(ss.get_channel_binding("tls-unique"))
Antoine Pitroud6494802011-07-21 01:11:30 +0200862 # the same for server-side
863 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200864 with test_wrap_socket(s, server_side=True, certfile=CERTFILE) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100865 self.assertIsNone(ss.get_channel_binding("tls-unique"))
Antoine Pitroud6494802011-07-21 01:11:30 +0200866
Benjamin Peterson36f7b972013-01-10 14:16:20 -0600867 def test_dealloc_warn(self):
Christian Heimesd0486372016-09-10 23:23:33 +0200868 ss = test_wrap_socket(socket.socket(socket.AF_INET))
Benjamin Peterson36f7b972013-01-10 14:16:20 -0600869 r = repr(ss)
870 with self.assertWarns(ResourceWarning) as cm:
871 ss = None
872 support.gc_collect()
873 self.assertIn(r, str(cm.warning.args[0]))
874
Christian Heimes6d7ad132013-06-09 18:02:55 +0200875 def test_get_default_verify_paths(self):
876 paths = ssl.get_default_verify_paths()
877 self.assertEqual(len(paths), 6)
878 self.assertIsInstance(paths, ssl.DefaultVerifyPaths)
879
Hai Shia7f5d932020-08-04 00:41:24 +0800880 with os_helper.EnvironmentVarGuard() as env:
Christian Heimes6d7ad132013-06-09 18:02:55 +0200881 env["SSL_CERT_DIR"] = CAPATH
882 env["SSL_CERT_FILE"] = CERTFILE
883 paths = ssl.get_default_verify_paths()
884 self.assertEqual(paths.cafile, CERTFILE)
885 self.assertEqual(paths.capath, CAPATH)
886
Christian Heimes44109d72013-11-22 01:51:30 +0100887 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
888 def test_enum_certificates(self):
889 self.assertTrue(ssl.enum_certificates("CA"))
890 self.assertTrue(ssl.enum_certificates("ROOT"))
891
892 self.assertRaises(TypeError, ssl.enum_certificates)
893 self.assertRaises(WindowsError, ssl.enum_certificates, "")
894
Christian Heimesc2d65e12013-11-22 16:13:55 +0100895 trust_oids = set()
896 for storename in ("CA", "ROOT"):
897 store = ssl.enum_certificates(storename)
898 self.assertIsInstance(store, list)
899 for element in store:
900 self.assertIsInstance(element, tuple)
901 self.assertEqual(len(element), 3)
902 cert, enc, trust = element
903 self.assertIsInstance(cert, bytes)
904 self.assertIn(enc, {"x509_asn", "pkcs_7_asn"})
Christian Heimes915cd3f2019-09-09 18:06:55 +0200905 self.assertIsInstance(trust, (frozenset, set, bool))
906 if isinstance(trust, (frozenset, set)):
Christian Heimesc2d65e12013-11-22 16:13:55 +0100907 trust_oids.update(trust)
Christian Heimes44109d72013-11-22 01:51:30 +0100908
909 serverAuth = "1.3.6.1.5.5.7.3.1"
Christian Heimesc2d65e12013-11-22 16:13:55 +0100910 self.assertIn(serverAuth, trust_oids)
Christian Heimes6d7ad132013-06-09 18:02:55 +0200911
Christian Heimes46bebee2013-06-09 19:03:31 +0200912 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
Christian Heimes44109d72013-11-22 01:51:30 +0100913 def test_enum_crls(self):
914 self.assertTrue(ssl.enum_crls("CA"))
915 self.assertRaises(TypeError, ssl.enum_crls)
916 self.assertRaises(WindowsError, ssl.enum_crls, "")
Christian Heimes46bebee2013-06-09 19:03:31 +0200917
Christian Heimes44109d72013-11-22 01:51:30 +0100918 crls = ssl.enum_crls("CA")
919 self.assertIsInstance(crls, list)
920 for element in crls:
921 self.assertIsInstance(element, tuple)
922 self.assertEqual(len(element), 2)
923 self.assertIsInstance(element[0], bytes)
924 self.assertIn(element[1], {"x509_asn", "pkcs_7_asn"})
Christian Heimes46bebee2013-06-09 19:03:31 +0200925
Christian Heimes46bebee2013-06-09 19:03:31 +0200926
Christian Heimesa6bc95a2013-11-17 19:59:14 +0100927 def test_asn1object(self):
928 expected = (129, 'serverAuth', 'TLS Web Server Authentication',
929 '1.3.6.1.5.5.7.3.1')
930
931 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1')
932 self.assertEqual(val, expected)
933 self.assertEqual(val.nid, 129)
934 self.assertEqual(val.shortname, 'serverAuth')
935 self.assertEqual(val.longname, 'TLS Web Server Authentication')
936 self.assertEqual(val.oid, '1.3.6.1.5.5.7.3.1')
937 self.assertIsInstance(val, ssl._ASN1Object)
938 self.assertRaises(ValueError, ssl._ASN1Object, 'serverAuth')
939
940 val = ssl._ASN1Object.fromnid(129)
941 self.assertEqual(val, expected)
942 self.assertIsInstance(val, ssl._ASN1Object)
943 self.assertRaises(ValueError, ssl._ASN1Object.fromnid, -1)
Christian Heimes5398e1a2013-11-22 16:20:53 +0100944 with self.assertRaisesRegex(ValueError, "unknown NID 100000"):
945 ssl._ASN1Object.fromnid(100000)
Christian Heimesa6bc95a2013-11-17 19:59:14 +0100946 for i in range(1000):
947 try:
948 obj = ssl._ASN1Object.fromnid(i)
949 except ValueError:
950 pass
951 else:
952 self.assertIsInstance(obj.nid, int)
953 self.assertIsInstance(obj.shortname, str)
954 self.assertIsInstance(obj.longname, str)
955 self.assertIsInstance(obj.oid, (str, type(None)))
956
957 val = ssl._ASN1Object.fromname('TLS Web Server Authentication')
958 self.assertEqual(val, expected)
959 self.assertIsInstance(val, ssl._ASN1Object)
960 self.assertEqual(ssl._ASN1Object.fromname('serverAuth'), expected)
961 self.assertEqual(ssl._ASN1Object.fromname('1.3.6.1.5.5.7.3.1'),
962 expected)
Christian Heimes5398e1a2013-11-22 16:20:53 +0100963 with self.assertRaisesRegex(ValueError, "unknown object 'serverauth'"):
964 ssl._ASN1Object.fromname('serverauth')
Christian Heimesa6bc95a2013-11-17 19:59:14 +0100965
Christian Heimes72d28502013-11-23 13:56:58 +0100966 def test_purpose_enum(self):
967 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1')
968 self.assertIsInstance(ssl.Purpose.SERVER_AUTH, ssl._ASN1Object)
969 self.assertEqual(ssl.Purpose.SERVER_AUTH, val)
970 self.assertEqual(ssl.Purpose.SERVER_AUTH.nid, 129)
971 self.assertEqual(ssl.Purpose.SERVER_AUTH.shortname, 'serverAuth')
972 self.assertEqual(ssl.Purpose.SERVER_AUTH.oid,
973 '1.3.6.1.5.5.7.3.1')
974
975 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.2')
976 self.assertIsInstance(ssl.Purpose.CLIENT_AUTH, ssl._ASN1Object)
977 self.assertEqual(ssl.Purpose.CLIENT_AUTH, val)
978 self.assertEqual(ssl.Purpose.CLIENT_AUTH.nid, 130)
979 self.assertEqual(ssl.Purpose.CLIENT_AUTH.shortname, 'clientAuth')
980 self.assertEqual(ssl.Purpose.CLIENT_AUTH.oid,
981 '1.3.6.1.5.5.7.3.2')
982
Antoine Pitrou3e86ba42013-12-28 17:26:33 +0100983 def test_unsupported_dtls(self):
984 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
985 self.addCleanup(s.close)
986 with self.assertRaises(NotImplementedError) as cx:
Christian Heimesd0486372016-09-10 23:23:33 +0200987 test_wrap_socket(s, cert_reqs=ssl.CERT_NONE)
Antoine Pitrou3e86ba42013-12-28 17:26:33 +0100988 self.assertEqual(str(cx.exception), "only stream sockets are supported")
Christian Heimesa170fa12017-09-15 20:27:30 +0200989 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou3e86ba42013-12-28 17:26:33 +0100990 with self.assertRaises(NotImplementedError) as cx:
991 ctx.wrap_socket(s)
992 self.assertEqual(str(cx.exception), "only stream sockets are supported")
993
Antoine Pitrouc695c952014-04-28 20:57:36 +0200994 def cert_time_ok(self, timestring, timestamp):
995 self.assertEqual(ssl.cert_time_to_seconds(timestring), timestamp)
996
997 def cert_time_fail(self, timestring):
998 with self.assertRaises(ValueError):
999 ssl.cert_time_to_seconds(timestring)
1000
1001 @unittest.skipUnless(utc_offset(),
1002 'local time needs to be different from UTC')
1003 def test_cert_time_to_seconds_timezone(self):
1004 # Issue #19940: ssl.cert_time_to_seconds() returns wrong
1005 # results if local timezone is not UTC
1006 self.cert_time_ok("May 9 00:00:00 2007 GMT", 1178668800.0)
1007 self.cert_time_ok("Jan 5 09:34:43 2018 GMT", 1515144883.0)
1008
1009 def test_cert_time_to_seconds(self):
1010 timestring = "Jan 5 09:34:43 2018 GMT"
1011 ts = 1515144883.0
1012 self.cert_time_ok(timestring, ts)
1013 # accept keyword parameter, assert its name
1014 self.assertEqual(ssl.cert_time_to_seconds(cert_time=timestring), ts)
1015 # accept both %e and %d (space or zero generated by strftime)
1016 self.cert_time_ok("Jan 05 09:34:43 2018 GMT", ts)
1017 # case-insensitive
1018 self.cert_time_ok("JaN 5 09:34:43 2018 GmT", ts)
1019 self.cert_time_fail("Jan 5 09:34 2018 GMT") # no seconds
1020 self.cert_time_fail("Jan 5 09:34:43 2018") # no GMT
1021 self.cert_time_fail("Jan 5 09:34:43 2018 UTC") # not GMT timezone
1022 self.cert_time_fail("Jan 35 09:34:43 2018 GMT") # invalid day
1023 self.cert_time_fail("Jon 5 09:34:43 2018 GMT") # invalid month
1024 self.cert_time_fail("Jan 5 24:00:00 2018 GMT") # invalid hour
1025 self.cert_time_fail("Jan 5 09:60:43 2018 GMT") # invalid minute
1026
1027 newyear_ts = 1230768000.0
1028 # leap seconds
1029 self.cert_time_ok("Dec 31 23:59:60 2008 GMT", newyear_ts)
1030 # same timestamp
1031 self.cert_time_ok("Jan 1 00:00:00 2009 GMT", newyear_ts)
1032
1033 self.cert_time_ok("Jan 5 09:34:59 2018 GMT", 1515144899)
1034 # allow 60th second (even if it is not a leap second)
1035 self.cert_time_ok("Jan 5 09:34:60 2018 GMT", 1515144900)
1036 # allow 2nd leap second for compatibility with time.strptime()
1037 self.cert_time_ok("Jan 5 09:34:61 2018 GMT", 1515144901)
1038 self.cert_time_fail("Jan 5 09:34:62 2018 GMT") # invalid seconds
1039
Mike53f7a7c2017-12-14 14:04:53 +03001040 # no special treatment for the special value:
Antoine Pitrouc695c952014-04-28 20:57:36 +02001041 # 99991231235959Z (rfc 5280)
1042 self.cert_time_ok("Dec 31 23:59:59 9999 GMT", 253402300799.0)
1043
1044 @support.run_with_locale('LC_ALL', '')
1045 def test_cert_time_to_seconds_locale(self):
1046 # `cert_time_to_seconds()` should be locale independent
1047
1048 def local_february_name():
1049 return time.strftime('%b', (1, 2, 3, 4, 5, 6, 0, 0, 0))
1050
1051 if local_february_name().lower() == 'feb':
1052 self.skipTest("locale-specific month name needs to be "
1053 "different from C locale")
1054
1055 # locale-independent
1056 self.cert_time_ok("Feb 9 00:00:00 2007 GMT", 1170979200.0)
1057 self.cert_time_fail(local_february_name() + " 9 00:00:00 2007 GMT")
1058
Martin Panter3840b2a2016-03-27 01:53:46 +00001059 def test_connect_ex_error(self):
1060 server = socket.socket(socket.AF_INET)
1061 self.addCleanup(server.close)
Serhiy Storchaka16994912020-04-25 10:06:29 +03001062 port = socket_helper.bind_port(server) # Reserve port but don't listen
Christian Heimesd0486372016-09-10 23:23:33 +02001063 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001064 cert_reqs=ssl.CERT_REQUIRED)
1065 self.addCleanup(s.close)
1066 rc = s.connect_ex((HOST, port))
1067 # Issue #19919: Windows machines or VMs hosted on Windows
1068 # machines sometimes return EWOULDBLOCK.
1069 errors = (
1070 errno.ECONNREFUSED, errno.EHOSTUNREACH, errno.ETIMEDOUT,
1071 errno.EWOULDBLOCK,
1072 )
1073 self.assertIn(rc, errors)
1074
Christian Heimes89d15502021-04-19 06:55:30 +02001075 def test_read_write_zero(self):
1076 # empty reads and writes now work, bpo-42854, bpo-31711
1077 client_context, server_context, hostname = testing_context()
1078 server = ThreadedEchoServer(context=server_context)
1079 with server:
1080 with client_context.wrap_socket(socket.socket(),
1081 server_hostname=hostname) as s:
1082 s.connect((HOST, server.port))
1083 self.assertEqual(s.recv(0), b"")
1084 self.assertEqual(s.send(b""), 0)
1085
Christian Heimesa6bc95a2013-11-17 19:59:14 +01001086
Antoine Pitrou152efa22010-05-16 18:19:27 +00001087class ContextTests(unittest.TestCase):
1088
1089 def test_constructor(self):
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01001090 for protocol in PROTOCOLS:
Christian Heimes2875c602021-04-19 07:27:10 +02001091 with warnings_helper.check_warnings():
1092 ctx = ssl.SSLContext(protocol)
1093 self.assertEqual(ctx.protocol, protocol)
1094 with warnings_helper.check_warnings():
1095 ctx = ssl.SSLContext()
Christian Heimes598894f2016-09-05 23:19:05 +02001096 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001097 self.assertRaises(ValueError, ssl.SSLContext, -1)
1098 self.assertRaises(ValueError, ssl.SSLContext, 42)
1099
Antoine Pitrou152efa22010-05-16 18:19:27 +00001100 def test_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001101 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001102 ctx.set_ciphers("ALL")
1103 ctx.set_ciphers("DEFAULT")
Ezio Melottied3a7d22010-12-01 02:32:32 +00001104 with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
Antoine Pitrou30474062010-05-16 23:46:26 +00001105 ctx.set_ciphers("^$:,;?*'dorothyx")
Antoine Pitrou152efa22010-05-16 18:19:27 +00001106
Christian Heimes892d66e2018-01-29 14:10:18 +01001107 @unittest.skipUnless(PY_SSL_DEFAULT_CIPHERS == 1,
1108 "Test applies only to Python default ciphers")
1109 def test_python_ciphers(self):
1110 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1111 ciphers = ctx.get_ciphers()
1112 for suite in ciphers:
1113 name = suite['name']
1114 self.assertNotIn("PSK", name)
1115 self.assertNotIn("SRP", name)
1116 self.assertNotIn("MD5", name)
1117 self.assertNotIn("RC4", name)
1118 self.assertNotIn("3DES", name)
1119
Christian Heimes25bfcd52016-09-06 00:04:45 +02001120 def test_get_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001121 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesea9b2dc2016-09-06 10:45:44 +02001122 ctx.set_ciphers('AESGCM')
Christian Heimes25bfcd52016-09-06 00:04:45 +02001123 names = set(d['name'] for d in ctx.get_ciphers())
Christian Heimes582282b2016-09-06 11:27:25 +02001124 self.assertIn('AES256-GCM-SHA384', names)
1125 self.assertIn('AES128-GCM-SHA256', names)
Christian Heimes25bfcd52016-09-06 00:04:45 +02001126
Antoine Pitroub5218772010-05-21 09:56:06 +00001127 def test_options(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001128 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Benjamin Petersona9dcdab2015-11-11 22:38:41 -08001129 # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value
Christian Heimes598894f2016-09-05 23:19:05 +02001130 default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
Christian Heimes358cfd42016-09-10 22:43:48 +02001131 # SSLContext also enables these by default
1132 default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE |
Christian Heimes05d9fe32018-02-27 08:55:39 +01001133 OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE |
Christian Heimes6f37ebc2021-04-09 17:59:21 +02001134 OP_ENABLE_MIDDLEBOX_COMPAT |
1135 OP_IGNORE_UNEXPECTED_EOF)
Christian Heimes598894f2016-09-05 23:19:05 +02001136 self.assertEqual(default, ctx.options)
Christian Heimes2875c602021-04-19 07:27:10 +02001137 with warnings_helper.check_warnings():
1138 ctx.options |= ssl.OP_NO_TLSv1
Christian Heimes598894f2016-09-05 23:19:05 +02001139 self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options)
Christian Heimes2875c602021-04-19 07:27:10 +02001140 with warnings_helper.check_warnings():
1141 ctx.options = (ctx.options & ~ssl.OP_NO_TLSv1)
Christian Heimes39258d32021-04-17 11:36:35 +02001142 self.assertEqual(default, ctx.options)
1143 ctx.options = 0
1144 # Ubuntu has OP_NO_SSLv3 forced on by default
1145 self.assertEqual(0, ctx.options & ~ssl.OP_NO_SSLv3)
Antoine Pitroub5218772010-05-21 09:56:06 +00001146
Christian Heimesa170fa12017-09-15 20:27:30 +02001147 def test_verify_mode_protocol(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001148 with warnings_helper.check_warnings():
1149 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001150 # Default value
1151 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1152 ctx.verify_mode = ssl.CERT_OPTIONAL
1153 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1154 ctx.verify_mode = ssl.CERT_REQUIRED
1155 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1156 ctx.verify_mode = ssl.CERT_NONE
1157 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1158 with self.assertRaises(TypeError):
1159 ctx.verify_mode = None
1160 with self.assertRaises(ValueError):
1161 ctx.verify_mode = 42
1162
Christian Heimesa170fa12017-09-15 20:27:30 +02001163 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1164 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1165 self.assertFalse(ctx.check_hostname)
1166
1167 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1168 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1169 self.assertTrue(ctx.check_hostname)
1170
Christian Heimes61d478c2018-01-27 15:51:38 +01001171 def test_hostname_checks_common_name(self):
1172 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1173 self.assertTrue(ctx.hostname_checks_common_name)
1174 if ssl.HAS_NEVER_CHECK_COMMON_NAME:
1175 ctx.hostname_checks_common_name = True
1176 self.assertTrue(ctx.hostname_checks_common_name)
1177 ctx.hostname_checks_common_name = False
1178 self.assertFalse(ctx.hostname_checks_common_name)
1179 ctx.hostname_checks_common_name = True
1180 self.assertTrue(ctx.hostname_checks_common_name)
1181 else:
1182 with self.assertRaises(AttributeError):
1183 ctx.hostname_checks_common_name = True
Christian Heimesa170fa12017-09-15 20:27:30 +02001184
Christian Heimes2875c602021-04-19 07:27:10 +02001185 @ignore_deprecation
Christian Heimes698dde12018-02-27 11:54:43 +01001186 def test_min_max_version(self):
1187 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimes34de2d32019-01-18 16:09:30 +01001188 # OpenSSL default is MINIMUM_SUPPORTED, however some vendors like
1189 # Fedora override the setting to TLS 1.0.
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001190 minimum_range = {
1191 # stock OpenSSL
1192 ssl.TLSVersion.MINIMUM_SUPPORTED,
1193 # Fedora 29 uses TLS 1.0 by default
1194 ssl.TLSVersion.TLSv1,
1195 # RHEL 8 uses TLS 1.2 by default
1196 ssl.TLSVersion.TLSv1_2
1197 }
torsava34864d12019-12-02 17:15:42 +01001198 maximum_range = {
1199 # stock OpenSSL
1200 ssl.TLSVersion.MAXIMUM_SUPPORTED,
1201 # Fedora 32 uses TLS 1.3 by default
1202 ssl.TLSVersion.TLSv1_3
1203 }
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001204
Christian Heimes34de2d32019-01-18 16:09:30 +01001205 self.assertIn(
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001206 ctx.minimum_version, minimum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001207 )
torsava34864d12019-12-02 17:15:42 +01001208 self.assertIn(
1209 ctx.maximum_version, maximum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001210 )
1211
1212 ctx.minimum_version = ssl.TLSVersion.TLSv1_1
1213 ctx.maximum_version = ssl.TLSVersion.TLSv1_2
1214 self.assertEqual(
1215 ctx.minimum_version, ssl.TLSVersion.TLSv1_1
1216 )
1217 self.assertEqual(
1218 ctx.maximum_version, ssl.TLSVersion.TLSv1_2
1219 )
1220
1221 ctx.minimum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1222 ctx.maximum_version = ssl.TLSVersion.TLSv1
1223 self.assertEqual(
1224 ctx.minimum_version, ssl.TLSVersion.MINIMUM_SUPPORTED
1225 )
1226 self.assertEqual(
1227 ctx.maximum_version, ssl.TLSVersion.TLSv1
1228 )
1229
1230 ctx.maximum_version = ssl.TLSVersion.MAXIMUM_SUPPORTED
1231 self.assertEqual(
1232 ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED
1233 )
1234
1235 ctx.maximum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1236 self.assertIn(
1237 ctx.maximum_version,
1238 {ssl.TLSVersion.TLSv1, ssl.TLSVersion.SSLv3}
1239 )
1240
1241 ctx.minimum_version = ssl.TLSVersion.MAXIMUM_SUPPORTED
1242 self.assertIn(
1243 ctx.minimum_version,
1244 {ssl.TLSVersion.TLSv1_2, ssl.TLSVersion.TLSv1_3}
1245 )
1246
1247 with self.assertRaises(ValueError):
1248 ctx.minimum_version = 42
1249
1250 ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_1)
1251
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001252 self.assertIn(
1253 ctx.minimum_version, minimum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001254 )
1255 self.assertEqual(
1256 ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED
1257 )
1258 with self.assertRaises(ValueError):
1259 ctx.minimum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1260 with self.assertRaises(ValueError):
1261 ctx.maximum_version = ssl.TLSVersion.TLSv1
1262
1263
matthewhughes9348e836bb2020-07-17 09:59:15 +01001264 @unittest.skipUnless(
1265 hasattr(ssl.SSLContext, 'security_level'),
1266 "requires OpenSSL >= 1.1.0"
1267 )
1268 def test_security_level(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001269 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
matthewhughes9348e836bb2020-07-17 09:59:15 +01001270 # The default security callback allows for levels between 0-5
1271 # with OpenSSL defaulting to 1, however some vendors override the
1272 # default value (e.g. Debian defaults to 2)
1273 security_level_range = {
1274 0,
1275 1, # OpenSSL default
1276 2, # Debian
1277 3,
1278 4,
1279 5,
1280 }
1281 self.assertIn(ctx.security_level, security_level_range)
1282
Christian Heimes22587792013-11-21 23:56:13 +01001283 def test_verify_flags(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001284 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Benjamin Peterson990fcaa2015-03-04 22:49:41 -05001285 # default value
1286 tf = getattr(ssl, "VERIFY_X509_TRUSTED_FIRST", 0)
1287 self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT | tf)
Christian Heimes22587792013-11-21 23:56:13 +01001288 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF
1289 self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_LEAF)
1290 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_CHAIN
1291 self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_CHAIN)
1292 ctx.verify_flags = ssl.VERIFY_DEFAULT
1293 self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT)
Chris Burre0b4aa02021-03-18 09:24:01 +01001294 ctx.verify_flags = ssl.VERIFY_ALLOW_PROXY_CERTS
1295 self.assertEqual(ctx.verify_flags, ssl.VERIFY_ALLOW_PROXY_CERTS)
Christian Heimes22587792013-11-21 23:56:13 +01001296 # supports any value
1297 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT
1298 self.assertEqual(ctx.verify_flags,
1299 ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT)
1300 with self.assertRaises(TypeError):
1301 ctx.verify_flags = None
1302
Antoine Pitrou152efa22010-05-16 18:19:27 +00001303 def test_load_cert_chain(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001304 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001305 # Combined key and cert in a single file
Benjamin Peterson1ea070e2014-11-03 21:05:01 -05001306 ctx.load_cert_chain(CERTFILE, keyfile=None)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001307 ctx.load_cert_chain(CERTFILE, keyfile=CERTFILE)
1308 self.assertRaises(TypeError, ctx.load_cert_chain, keyfile=CERTFILE)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001309 with self.assertRaises(OSError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001310 ctx.load_cert_chain(NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +00001311 self.assertEqual(cm.exception.errno, errno.ENOENT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001312 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001313 ctx.load_cert_chain(BADCERT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001314 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001315 ctx.load_cert_chain(EMPTYCERT)
1316 # Separate key and cert
Christian Heimesa170fa12017-09-15 20:27:30 +02001317 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001318 ctx.load_cert_chain(ONLYCERT, ONLYKEY)
1319 ctx.load_cert_chain(certfile=ONLYCERT, keyfile=ONLYKEY)
1320 ctx.load_cert_chain(certfile=BYTES_ONLYCERT, keyfile=BYTES_ONLYKEY)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001321 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001322 ctx.load_cert_chain(ONLYCERT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001323 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001324 ctx.load_cert_chain(ONLYKEY)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001325 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001326 ctx.load_cert_chain(certfile=ONLYKEY, keyfile=ONLYCERT)
1327 # Mismatching key and cert
Christian Heimesa170fa12017-09-15 20:27:30 +02001328 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001329 with self.assertRaisesRegex(ssl.SSLError, "key values mismatch"):
Martin Panter3d81d932016-01-14 09:36:00 +00001330 ctx.load_cert_chain(CAFILE_CACERT, ONLYKEY)
Antoine Pitrou4fd1e6a2011-08-25 14:39:44 +02001331 # Password protected key and cert
1332 ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD)
1333 ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD.encode())
1334 ctx.load_cert_chain(CERTFILE_PROTECTED,
1335 password=bytearray(KEY_PASSWORD.encode()))
1336 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD)
1337 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD.encode())
1338 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED,
1339 bytearray(KEY_PASSWORD.encode()))
1340 with self.assertRaisesRegex(TypeError, "should be a string"):
1341 ctx.load_cert_chain(CERTFILE_PROTECTED, password=True)
1342 with self.assertRaises(ssl.SSLError):
1343 ctx.load_cert_chain(CERTFILE_PROTECTED, password="badpass")
1344 with self.assertRaisesRegex(ValueError, "cannot be longer"):
1345 # openssl has a fixed limit on the password buffer.
1346 # PEM_BUFSIZE is generally set to 1kb.
1347 # Return a string larger than this.
1348 ctx.load_cert_chain(CERTFILE_PROTECTED, password=b'a' * 102400)
1349 # Password callback
1350 def getpass_unicode():
1351 return KEY_PASSWORD
1352 def getpass_bytes():
1353 return KEY_PASSWORD.encode()
1354 def getpass_bytearray():
1355 return bytearray(KEY_PASSWORD.encode())
1356 def getpass_badpass():
1357 return "badpass"
1358 def getpass_huge():
1359 return b'a' * (1024 * 1024)
1360 def getpass_bad_type():
1361 return 9
1362 def getpass_exception():
1363 raise Exception('getpass error')
1364 class GetPassCallable:
1365 def __call__(self):
1366 return KEY_PASSWORD
1367 def getpass(self):
1368 return KEY_PASSWORD
1369 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_unicode)
1370 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytes)
1371 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytearray)
1372 ctx.load_cert_chain(CERTFILE_PROTECTED, password=GetPassCallable())
1373 ctx.load_cert_chain(CERTFILE_PROTECTED,
1374 password=GetPassCallable().getpass)
1375 with self.assertRaises(ssl.SSLError):
1376 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_badpass)
1377 with self.assertRaisesRegex(ValueError, "cannot be longer"):
1378 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_huge)
1379 with self.assertRaisesRegex(TypeError, "must return a string"):
1380 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bad_type)
1381 with self.assertRaisesRegex(Exception, "getpass error"):
1382 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_exception)
1383 # Make sure the password function isn't called if it isn't needed
1384 ctx.load_cert_chain(CERTFILE, password=getpass_exception)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001385
1386 def test_load_verify_locations(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001387 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001388 ctx.load_verify_locations(CERTFILE)
1389 ctx.load_verify_locations(cafile=CERTFILE, capath=None)
1390 ctx.load_verify_locations(BYTES_CERTFILE)
1391 ctx.load_verify_locations(cafile=BYTES_CERTFILE, capath=None)
1392 self.assertRaises(TypeError, ctx.load_verify_locations)
Christian Heimesefff7062013-11-21 03:35:02 +01001393 self.assertRaises(TypeError, ctx.load_verify_locations, None, None, None)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001394 with self.assertRaises(OSError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001395 ctx.load_verify_locations(NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +00001396 self.assertEqual(cm.exception.errno, errno.ENOENT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001397 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001398 ctx.load_verify_locations(BADCERT)
1399 ctx.load_verify_locations(CERTFILE, CAPATH)
1400 ctx.load_verify_locations(CERTFILE, capath=BYTES_CAPATH)
1401
Victor Stinner80f75e62011-01-29 11:31:20 +00001402 # Issue #10989: crash if the second argument type is invalid
1403 self.assertRaises(TypeError, ctx.load_verify_locations, None, True)
1404
Christian Heimesefff7062013-11-21 03:35:02 +01001405 def test_load_verify_cadata(self):
1406 # test cadata
1407 with open(CAFILE_CACERT) as f:
1408 cacert_pem = f.read()
1409 cacert_der = ssl.PEM_cert_to_DER_cert(cacert_pem)
1410 with open(CAFILE_NEURONIO) as f:
1411 neuronio_pem = f.read()
1412 neuronio_der = ssl.PEM_cert_to_DER_cert(neuronio_pem)
1413
1414 # test PEM
Christian Heimesa170fa12017-09-15 20:27:30 +02001415 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001416 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 0)
1417 ctx.load_verify_locations(cadata=cacert_pem)
1418 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 1)
1419 ctx.load_verify_locations(cadata=neuronio_pem)
1420 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1421 # cert already in hash table
1422 ctx.load_verify_locations(cadata=neuronio_pem)
1423 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1424
1425 # combined
Christian Heimesa170fa12017-09-15 20:27:30 +02001426 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001427 combined = "\n".join((cacert_pem, neuronio_pem))
1428 ctx.load_verify_locations(cadata=combined)
1429 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1430
1431 # with junk around the certs
Christian Heimesa170fa12017-09-15 20:27:30 +02001432 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001433 combined = ["head", cacert_pem, "other", neuronio_pem, "again",
1434 neuronio_pem, "tail"]
1435 ctx.load_verify_locations(cadata="\n".join(combined))
1436 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1437
1438 # test DER
Christian Heimesa170fa12017-09-15 20:27:30 +02001439 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001440 ctx.load_verify_locations(cadata=cacert_der)
1441 ctx.load_verify_locations(cadata=neuronio_der)
1442 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1443 # cert already in hash table
1444 ctx.load_verify_locations(cadata=cacert_der)
1445 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1446
1447 # combined
Christian Heimesa170fa12017-09-15 20:27:30 +02001448 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001449 combined = b"".join((cacert_der, neuronio_der))
1450 ctx.load_verify_locations(cadata=combined)
1451 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1452
1453 # error cases
Christian Heimesa170fa12017-09-15 20:27:30 +02001454 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001455 self.assertRaises(TypeError, ctx.load_verify_locations, cadata=object)
1456
Christian Heimesb9ad88b2021-04-23 13:51:40 +02001457 with self.assertRaisesRegex(
1458 ssl.SSLError,
1459 "no start line: cadata does not contain a certificate"
1460 ):
Christian Heimesefff7062013-11-21 03:35:02 +01001461 ctx.load_verify_locations(cadata="broken")
Christian Heimesb9ad88b2021-04-23 13:51:40 +02001462 with self.assertRaisesRegex(
1463 ssl.SSLError,
1464 "not enough data: cadata does not contain a certificate"
1465 ):
Christian Heimesefff7062013-11-21 03:35:02 +01001466 ctx.load_verify_locations(cadata=b"broken")
1467
Paul Monsonf3550692019-06-19 13:09:54 -07001468 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001469 def test_load_dh_params(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001470 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001471 ctx.load_dh_params(DHFILE)
1472 if os.name != 'nt':
1473 ctx.load_dh_params(BYTES_DHFILE)
1474 self.assertRaises(TypeError, ctx.load_dh_params)
1475 self.assertRaises(TypeError, ctx.load_dh_params, None)
1476 with self.assertRaises(FileNotFoundError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001477 ctx.load_dh_params(NONEXISTINGCERT)
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001478 self.assertEqual(cm.exception.errno, errno.ENOENT)
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001479 with self.assertRaises(ssl.SSLError) as cm:
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001480 ctx.load_dh_params(CERTFILE)
1481
Antoine Pitroub0182c82010-10-12 20:09:02 +00001482 def test_session_stats(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001483 for proto in {ssl.PROTOCOL_TLS_CLIENT, ssl.PROTOCOL_TLS_SERVER}:
Antoine Pitroub0182c82010-10-12 20:09:02 +00001484 ctx = ssl.SSLContext(proto)
1485 self.assertEqual(ctx.session_stats(), {
1486 'number': 0,
1487 'connect': 0,
1488 'connect_good': 0,
1489 'connect_renegotiate': 0,
1490 'accept': 0,
1491 'accept_good': 0,
1492 'accept_renegotiate': 0,
1493 'hits': 0,
1494 'misses': 0,
1495 'timeouts': 0,
1496 'cache_full': 0,
1497 })
1498
Antoine Pitrou664c2d12010-11-17 20:29:42 +00001499 def test_set_default_verify_paths(self):
1500 # There's not much we can do to test that it acts as expected,
1501 # so just check it doesn't crash or raise an exception.
Christian Heimesa170fa12017-09-15 20:27:30 +02001502 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou664c2d12010-11-17 20:29:42 +00001503 ctx.set_default_verify_paths()
1504
Antoine Pitrou501da612011-12-21 09:27:41 +01001505 @unittest.skipUnless(ssl.HAS_ECDH, "ECDH disabled on this OpenSSL build")
Antoine Pitrou923df6f2011-12-19 17:16:51 +01001506 def test_set_ecdh_curve(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001507 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou923df6f2011-12-19 17:16:51 +01001508 ctx.set_ecdh_curve("prime256v1")
1509 ctx.set_ecdh_curve(b"prime256v1")
1510 self.assertRaises(TypeError, ctx.set_ecdh_curve)
1511 self.assertRaises(TypeError, ctx.set_ecdh_curve, None)
1512 self.assertRaises(ValueError, ctx.set_ecdh_curve, "foo")
1513 self.assertRaises(ValueError, ctx.set_ecdh_curve, b"foo")
1514
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001515 def test_sni_callback(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001516 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001517
1518 # set_servername_callback expects a callable, or None
1519 self.assertRaises(TypeError, ctx.set_servername_callback)
1520 self.assertRaises(TypeError, ctx.set_servername_callback, 4)
1521 self.assertRaises(TypeError, ctx.set_servername_callback, "")
1522 self.assertRaises(TypeError, ctx.set_servername_callback, ctx)
1523
1524 def dummycallback(sock, servername, ctx):
1525 pass
1526 ctx.set_servername_callback(None)
1527 ctx.set_servername_callback(dummycallback)
1528
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001529 def test_sni_callback_refcycle(self):
1530 # Reference cycles through the servername callback are detected
1531 # and cleared.
Christian Heimesa170fa12017-09-15 20:27:30 +02001532 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001533 def dummycallback(sock, servername, ctx, cycle=ctx):
1534 pass
1535 ctx.set_servername_callback(dummycallback)
1536 wr = weakref.ref(ctx)
1537 del ctx, dummycallback
1538 gc.collect()
1539 self.assertIs(wr(), None)
1540
Christian Heimes9a5395a2013-06-17 15:44:12 +02001541 def test_cert_store_stats(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001542 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001543 self.assertEqual(ctx.cert_store_stats(),
1544 {'x509_ca': 0, 'crl': 0, 'x509': 0})
1545 ctx.load_cert_chain(CERTFILE)
1546 self.assertEqual(ctx.cert_store_stats(),
1547 {'x509_ca': 0, 'crl': 0, 'x509': 0})
1548 ctx.load_verify_locations(CERTFILE)
1549 self.assertEqual(ctx.cert_store_stats(),
1550 {'x509_ca': 0, 'crl': 0, 'x509': 1})
Martin Panterb55f8b72016-01-14 12:53:56 +00001551 ctx.load_verify_locations(CAFILE_CACERT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001552 self.assertEqual(ctx.cert_store_stats(),
1553 {'x509_ca': 1, 'crl': 0, 'x509': 2})
1554
1555 def test_get_ca_certs(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001556 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001557 self.assertEqual(ctx.get_ca_certs(), [])
1558 # CERTFILE is not flagged as X509v3 Basic Constraints: CA:TRUE
1559 ctx.load_verify_locations(CERTFILE)
1560 self.assertEqual(ctx.get_ca_certs(), [])
Martin Panterb55f8b72016-01-14 12:53:56 +00001561 # but CAFILE_CACERT is a CA cert
1562 ctx.load_verify_locations(CAFILE_CACERT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001563 self.assertEqual(ctx.get_ca_certs(),
1564 [{'issuer': ((('organizationName', 'Root CA'),),
1565 (('organizationalUnitName', 'http://www.cacert.org'),),
1566 (('commonName', 'CA Cert Signing Authority'),),
1567 (('emailAddress', 'support@cacert.org'),)),
Christian Heimesd37b74f2021-04-19 08:31:29 +02001568 'notAfter': 'Mar 29 12:29:49 2033 GMT',
1569 'notBefore': 'Mar 30 12:29:49 2003 GMT',
Christian Heimes9a5395a2013-06-17 15:44:12 +02001570 'serialNumber': '00',
Christian Heimesbd3a7f92013-11-21 03:40:15 +01001571 'crlDistributionPoints': ('https://www.cacert.org/revoke.crl',),
Christian Heimes9a5395a2013-06-17 15:44:12 +02001572 'subject': ((('organizationName', 'Root CA'),),
1573 (('organizationalUnitName', 'http://www.cacert.org'),),
1574 (('commonName', 'CA Cert Signing Authority'),),
1575 (('emailAddress', 'support@cacert.org'),)),
1576 'version': 3}])
1577
Martin Panterb55f8b72016-01-14 12:53:56 +00001578 with open(CAFILE_CACERT) as f:
Christian Heimes9a5395a2013-06-17 15:44:12 +02001579 pem = f.read()
1580 der = ssl.PEM_cert_to_DER_cert(pem)
1581 self.assertEqual(ctx.get_ca_certs(True), [der])
1582
Christian Heimes72d28502013-11-23 13:56:58 +01001583 def test_load_default_certs(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001584 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001585 ctx.load_default_certs()
1586
Christian Heimesa170fa12017-09-15 20:27:30 +02001587 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001588 ctx.load_default_certs(ssl.Purpose.SERVER_AUTH)
1589 ctx.load_default_certs()
1590
Christian Heimesa170fa12017-09-15 20:27:30 +02001591 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001592 ctx.load_default_certs(ssl.Purpose.CLIENT_AUTH)
1593
Christian Heimesa170fa12017-09-15 20:27:30 +02001594 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001595 self.assertRaises(TypeError, ctx.load_default_certs, None)
1596 self.assertRaises(TypeError, ctx.load_default_certs, 'SERVER_AUTH')
1597
Benjamin Peterson91244e02014-10-03 18:17:15 -04001598 @unittest.skipIf(sys.platform == "win32", "not-Windows specific")
Benjamin Peterson5915b0f2014-10-03 17:27:05 -04001599 def test_load_default_certs_env(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001600 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Hai Shia7f5d932020-08-04 00:41:24 +08001601 with os_helper.EnvironmentVarGuard() as env:
Benjamin Peterson5915b0f2014-10-03 17:27:05 -04001602 env["SSL_CERT_DIR"] = CAPATH
1603 env["SSL_CERT_FILE"] = CERTFILE
1604 ctx.load_default_certs()
1605 self.assertEqual(ctx.cert_store_stats(), {"crl": 0, "x509": 1, "x509_ca": 0})
1606
Benjamin Peterson91244e02014-10-03 18:17:15 -04001607 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
Steve Dower68d663c2017-07-17 11:15:48 +02001608 @unittest.skipIf(hasattr(sys, "gettotalrefcount"), "Debug build does not share environment between CRTs")
Benjamin Peterson91244e02014-10-03 18:17:15 -04001609 def test_load_default_certs_env_windows(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001610 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Benjamin Peterson91244e02014-10-03 18:17:15 -04001611 ctx.load_default_certs()
1612 stats = ctx.cert_store_stats()
1613
Christian Heimesa170fa12017-09-15 20:27:30 +02001614 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Hai Shia7f5d932020-08-04 00:41:24 +08001615 with os_helper.EnvironmentVarGuard() as env:
Benjamin Peterson91244e02014-10-03 18:17:15 -04001616 env["SSL_CERT_DIR"] = CAPATH
1617 env["SSL_CERT_FILE"] = CERTFILE
1618 ctx.load_default_certs()
1619 stats["x509"] += 1
1620 self.assertEqual(ctx.cert_store_stats(), stats)
1621
Christian Heimes358cfd42016-09-10 22:43:48 +02001622 def _assert_context_options(self, ctx):
1623 self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
1624 if OP_NO_COMPRESSION != 0:
1625 self.assertEqual(ctx.options & OP_NO_COMPRESSION,
1626 OP_NO_COMPRESSION)
1627 if OP_SINGLE_DH_USE != 0:
1628 self.assertEqual(ctx.options & OP_SINGLE_DH_USE,
1629 OP_SINGLE_DH_USE)
1630 if OP_SINGLE_ECDH_USE != 0:
1631 self.assertEqual(ctx.options & OP_SINGLE_ECDH_USE,
1632 OP_SINGLE_ECDH_USE)
1633 if OP_CIPHER_SERVER_PREFERENCE != 0:
1634 self.assertEqual(ctx.options & OP_CIPHER_SERVER_PREFERENCE,
1635 OP_CIPHER_SERVER_PREFERENCE)
1636
Christian Heimes4c05b472013-11-23 15:58:30 +01001637 def test_create_default_context(self):
1638 ctx = ssl.create_default_context()
Christian Heimes358cfd42016-09-10 22:43:48 +02001639
Christian Heimes2875c602021-04-19 07:27:10 +02001640 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes4c05b472013-11-23 15:58:30 +01001641 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001642 self.assertTrue(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001643 self._assert_context_options(ctx)
1644
Christian Heimes4c05b472013-11-23 15:58:30 +01001645 with open(SIGNING_CA) as f:
1646 cadata = f.read()
1647 ctx = ssl.create_default_context(cafile=SIGNING_CA, capath=CAPATH,
1648 cadata=cadata)
Christian Heimes2875c602021-04-19 07:27:10 +02001649 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes4c05b472013-11-23 15:58:30 +01001650 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes358cfd42016-09-10 22:43:48 +02001651 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001652
1653 ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
Christian Heimes2875c602021-04-19 07:27:10 +02001654 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_SERVER)
Christian Heimes4c05b472013-11-23 15:58:30 +01001655 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001656 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001657
Christian Heimes2875c602021-04-19 07:27:10 +02001658
1659
Christian Heimes67986f92013-11-23 22:43:47 +01001660 def test__create_stdlib_context(self):
1661 ctx = ssl._create_stdlib_context()
Christian Heimes2875c602021-04-19 07:27:10 +02001662 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes67986f92013-11-23 22:43:47 +01001663 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001664 self.assertFalse(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001665 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001666
Christian Heimes2875c602021-04-19 07:27:10 +02001667 with warnings_helper.check_warnings():
1668 ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1)
Christian Heimes67986f92013-11-23 22:43:47 +01001669 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
1670 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001671 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001672
Christian Heimes2875c602021-04-19 07:27:10 +02001673 with warnings_helper.check_warnings():
1674 ctx = ssl._create_stdlib_context(
1675 ssl.PROTOCOL_TLSv1_2,
1676 cert_reqs=ssl.CERT_REQUIRED,
1677 check_hostname=True
1678 )
1679 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1_2)
Christian Heimes67986f92013-11-23 22:43:47 +01001680 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimesa02c69a2013-12-02 20:59:28 +01001681 self.assertTrue(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001682 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001683
1684 ctx = ssl._create_stdlib_context(purpose=ssl.Purpose.CLIENT_AUTH)
Christian Heimes2875c602021-04-19 07:27:10 +02001685 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_SERVER)
Christian Heimes67986f92013-11-23 22:43:47 +01001686 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001687 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001688
Christian Heimes1aa9a752013-12-02 02:41:19 +01001689 def test_check_hostname(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001690 with warnings_helper.check_warnings():
1691 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001692 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001693 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001694
Christian Heimese82c0342017-09-15 20:29:57 +02001695 # Auto set CERT_REQUIRED
1696 ctx.check_hostname = True
1697 self.assertTrue(ctx.check_hostname)
1698 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1699 ctx.check_hostname = False
Christian Heimes1aa9a752013-12-02 02:41:19 +01001700 ctx.verify_mode = ssl.CERT_REQUIRED
1701 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001702 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001703
Christian Heimese82c0342017-09-15 20:29:57 +02001704 # Changing verify_mode does not affect check_hostname
1705 ctx.check_hostname = False
1706 ctx.verify_mode = ssl.CERT_NONE
1707 ctx.check_hostname = False
1708 self.assertFalse(ctx.check_hostname)
1709 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1710 # Auto set
Christian Heimes1aa9a752013-12-02 02:41:19 +01001711 ctx.check_hostname = True
1712 self.assertTrue(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001713 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1714
1715 ctx.check_hostname = False
1716 ctx.verify_mode = ssl.CERT_OPTIONAL
1717 ctx.check_hostname = False
1718 self.assertFalse(ctx.check_hostname)
1719 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1720 # keep CERT_OPTIONAL
1721 ctx.check_hostname = True
1722 self.assertTrue(ctx.check_hostname)
1723 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001724
1725 # Cannot set CERT_NONE with check_hostname enabled
1726 with self.assertRaises(ValueError):
1727 ctx.verify_mode = ssl.CERT_NONE
1728 ctx.check_hostname = False
1729 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001730 ctx.verify_mode = ssl.CERT_NONE
1731 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001732
Christian Heimes5fe668c2016-09-12 00:01:11 +02001733 def test_context_client_server(self):
1734 # PROTOCOL_TLS_CLIENT has sane defaults
1735 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1736 self.assertTrue(ctx.check_hostname)
1737 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1738
1739 # PROTOCOL_TLS_SERVER has different but also sane defaults
1740 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1741 self.assertFalse(ctx.check_hostname)
1742 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1743
Christian Heimes4df60f12017-09-15 20:26:05 +02001744 def test_context_custom_class(self):
1745 class MySSLSocket(ssl.SSLSocket):
1746 pass
1747
1748 class MySSLObject(ssl.SSLObject):
1749 pass
1750
1751 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1752 ctx.sslsocket_class = MySSLSocket
1753 ctx.sslobject_class = MySSLObject
1754
1755 with ctx.wrap_socket(socket.socket(), server_side=True) as sock:
1756 self.assertIsInstance(sock, MySSLSocket)
1757 obj = ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO())
1758 self.assertIsInstance(obj, MySSLObject)
1759
Christian Heimes78c7d522019-06-03 21:00:10 +02001760 def test_num_tickest(self):
1761 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1762 self.assertEqual(ctx.num_tickets, 2)
1763 ctx.num_tickets = 1
1764 self.assertEqual(ctx.num_tickets, 1)
1765 ctx.num_tickets = 0
1766 self.assertEqual(ctx.num_tickets, 0)
1767 with self.assertRaises(ValueError):
1768 ctx.num_tickets = -1
1769 with self.assertRaises(TypeError):
1770 ctx.num_tickets = None
1771
1772 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1773 self.assertEqual(ctx.num_tickets, 2)
1774 with self.assertRaises(ValueError):
1775 ctx.num_tickets = 1
1776
Antoine Pitrou152efa22010-05-16 18:19:27 +00001777
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001778class SSLErrorTests(unittest.TestCase):
1779
1780 def test_str(self):
1781 # The str() of a SSLError doesn't include the errno
1782 e = ssl.SSLError(1, "foo")
1783 self.assertEqual(str(e), "foo")
1784 self.assertEqual(e.errno, 1)
1785 # Same for a subclass
1786 e = ssl.SSLZeroReturnError(1, "foo")
1787 self.assertEqual(str(e), "foo")
1788 self.assertEqual(e.errno, 1)
1789
Paul Monsonf3550692019-06-19 13:09:54 -07001790 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001791 def test_lib_reason(self):
1792 # Test the library and reason attributes
Christian Heimesa170fa12017-09-15 20:27:30 +02001793 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001794 with self.assertRaises(ssl.SSLError) as cm:
1795 ctx.load_dh_params(CERTFILE)
1796 self.assertEqual(cm.exception.library, 'PEM')
1797 self.assertEqual(cm.exception.reason, 'NO_START_LINE')
1798 s = str(cm.exception)
1799 self.assertTrue(s.startswith("[PEM: NO_START_LINE] no start line"), s)
1800
1801 def test_subclass(self):
1802 # Check that the appropriate SSLError subclass is raised
1803 # (this only tests one of them)
Christian Heimesa170fa12017-09-15 20:27:30 +02001804 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1805 ctx.check_hostname = False
1806 ctx.verify_mode = ssl.CERT_NONE
Giampaolo Rodolaeb7e29f2019-04-09 00:34:02 +02001807 with socket.create_server(("127.0.0.1", 0)) as s:
1808 c = socket.create_connection(s.getsockname())
Antoine Pitroue1ceb502013-01-12 21:54:44 +01001809 c.setblocking(False)
1810 with ctx.wrap_socket(c, False, do_handshake_on_connect=False) as c:
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001811 with self.assertRaises(ssl.SSLWantReadError) as cm:
1812 c.do_handshake()
1813 s = str(cm.exception)
1814 self.assertTrue(s.startswith("The operation did not complete (read)"), s)
1815 # For compatibility
1816 self.assertEqual(cm.exception.errno, ssl.SSL_ERROR_WANT_READ)
1817
1818
Christian Heimes61d478c2018-01-27 15:51:38 +01001819 def test_bad_server_hostname(self):
1820 ctx = ssl.create_default_context()
1821 with self.assertRaises(ValueError):
1822 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1823 server_hostname="")
1824 with self.assertRaises(ValueError):
1825 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1826 server_hostname=".example.org")
Christian Heimesd02ac252018-03-25 12:36:13 +02001827 with self.assertRaises(TypeError):
1828 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1829 server_hostname="example.org\x00evil.com")
Christian Heimes61d478c2018-01-27 15:51:38 +01001830
1831
Antoine Pitroub1fdf472014-10-05 20:41:53 +02001832class MemoryBIOTests(unittest.TestCase):
1833
1834 def test_read_write(self):
1835 bio = ssl.MemoryBIO()
1836 bio.write(b'foo')
1837 self.assertEqual(bio.read(), b'foo')
1838 self.assertEqual(bio.read(), b'')
1839 bio.write(b'foo')
1840 bio.write(b'bar')
1841 self.assertEqual(bio.read(), b'foobar')
1842 self.assertEqual(bio.read(), b'')
1843 bio.write(b'baz')
1844 self.assertEqual(bio.read(2), b'ba')
1845 self.assertEqual(bio.read(1), b'z')
1846 self.assertEqual(bio.read(1), b'')
1847
1848 def test_eof(self):
1849 bio = ssl.MemoryBIO()
1850 self.assertFalse(bio.eof)
1851 self.assertEqual(bio.read(), b'')
1852 self.assertFalse(bio.eof)
1853 bio.write(b'foo')
1854 self.assertFalse(bio.eof)
1855 bio.write_eof()
1856 self.assertFalse(bio.eof)
1857 self.assertEqual(bio.read(2), b'fo')
1858 self.assertFalse(bio.eof)
1859 self.assertEqual(bio.read(1), b'o')
1860 self.assertTrue(bio.eof)
1861 self.assertEqual(bio.read(), b'')
1862 self.assertTrue(bio.eof)
1863
1864 def test_pending(self):
1865 bio = ssl.MemoryBIO()
1866 self.assertEqual(bio.pending, 0)
1867 bio.write(b'foo')
1868 self.assertEqual(bio.pending, 3)
1869 for i in range(3):
1870 bio.read(1)
1871 self.assertEqual(bio.pending, 3-i-1)
1872 for i in range(3):
1873 bio.write(b'x')
1874 self.assertEqual(bio.pending, i+1)
1875 bio.read()
1876 self.assertEqual(bio.pending, 0)
1877
1878 def test_buffer_types(self):
1879 bio = ssl.MemoryBIO()
1880 bio.write(b'foo')
1881 self.assertEqual(bio.read(), b'foo')
1882 bio.write(bytearray(b'bar'))
1883 self.assertEqual(bio.read(), b'bar')
1884 bio.write(memoryview(b'baz'))
1885 self.assertEqual(bio.read(), b'baz')
1886
1887 def test_error_types(self):
1888 bio = ssl.MemoryBIO()
1889 self.assertRaises(TypeError, bio.write, 'foo')
1890 self.assertRaises(TypeError, bio.write, None)
1891 self.assertRaises(TypeError, bio.write, True)
1892 self.assertRaises(TypeError, bio.write, 1)
1893
1894
Christian Heimes9d50ab52018-02-27 10:17:30 +01001895class SSLObjectTests(unittest.TestCase):
1896 def test_private_init(self):
1897 bio = ssl.MemoryBIO()
1898 with self.assertRaisesRegex(TypeError, "public constructor"):
1899 ssl.SSLObject(bio, bio)
1900
Nathaniel J. Smithc0da5822018-09-21 21:44:12 -07001901 def test_unwrap(self):
1902 client_ctx, server_ctx, hostname = testing_context()
1903 c_in = ssl.MemoryBIO()
1904 c_out = ssl.MemoryBIO()
1905 s_in = ssl.MemoryBIO()
1906 s_out = ssl.MemoryBIO()
1907 client = client_ctx.wrap_bio(c_in, c_out, server_hostname=hostname)
1908 server = server_ctx.wrap_bio(s_in, s_out, server_side=True)
1909
1910 # Loop on the handshake for a bit to get it settled
1911 for _ in range(5):
1912 try:
1913 client.do_handshake()
1914 except ssl.SSLWantReadError:
1915 pass
1916 if c_out.pending:
1917 s_in.write(c_out.read())
1918 try:
1919 server.do_handshake()
1920 except ssl.SSLWantReadError:
1921 pass
1922 if s_out.pending:
1923 c_in.write(s_out.read())
1924 # Now the handshakes should be complete (don't raise WantReadError)
1925 client.do_handshake()
1926 server.do_handshake()
1927
1928 # Now if we unwrap one side unilaterally, it should send close-notify
1929 # and raise WantReadError:
1930 with self.assertRaises(ssl.SSLWantReadError):
1931 client.unwrap()
1932
1933 # But server.unwrap() does not raise, because it reads the client's
1934 # close-notify:
1935 s_in.write(c_out.read())
1936 server.unwrap()
1937
1938 # And now that the client gets the server's close-notify, it doesn't
1939 # raise either.
1940 c_in.write(s_out.read())
1941 client.unwrap()
Christian Heimes9d50ab52018-02-27 10:17:30 +01001942
Martin Panter3840b2a2016-03-27 01:53:46 +00001943class SimpleBackgroundTests(unittest.TestCase):
Martin Panter3840b2a2016-03-27 01:53:46 +00001944 """Tests that connect to a simple server running in the background"""
1945
1946 def setUp(self):
juhovh49fdf112021-04-18 21:11:48 +10001947 self.server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1948 self.server_context.load_cert_chain(SIGNED_CERTFILE)
1949 server = ThreadedEchoServer(context=self.server_context)
Martin Panter3840b2a2016-03-27 01:53:46 +00001950 self.server_addr = (HOST, server.port)
1951 server.__enter__()
1952 self.addCleanup(server.__exit__, None, None, None)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001953
Antoine Pitrou480a1242010-04-28 21:37:09 +00001954 def test_connect(self):
Christian Heimesd0486372016-09-10 23:23:33 +02001955 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001956 cert_reqs=ssl.CERT_NONE) as s:
1957 s.connect(self.server_addr)
1958 self.assertEqual({}, s.getpeercert())
Christian Heimesa5d07652016-09-24 10:48:05 +02001959 self.assertFalse(s.server_side)
Antoine Pitrou350c7222010-09-09 13:31:46 +00001960
Martin Panter3840b2a2016-03-27 01:53:46 +00001961 # this should succeed because we specify the root cert
Christian Heimesd0486372016-09-10 23:23:33 +02001962 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001963 cert_reqs=ssl.CERT_REQUIRED,
1964 ca_certs=SIGNING_CA) as s:
1965 s.connect(self.server_addr)
1966 self.assertTrue(s.getpeercert())
Christian Heimesa5d07652016-09-24 10:48:05 +02001967 self.assertFalse(s.server_side)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001968
Martin Panter3840b2a2016-03-27 01:53:46 +00001969 def test_connect_fail(self):
1970 # This should fail because we have no verification certs. Connection
1971 # failure crashes ThreadedEchoServer, so run this in an independent
1972 # test method.
Christian Heimesd0486372016-09-10 23:23:33 +02001973 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001974 cert_reqs=ssl.CERT_REQUIRED)
1975 self.addCleanup(s.close)
1976 self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
1977 s.connect, self.server_addr)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001978
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00001979 def test_connect_ex(self):
1980 # Issue #11326: check connect_ex() implementation
Christian Heimesd0486372016-09-10 23:23:33 +02001981 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001982 cert_reqs=ssl.CERT_REQUIRED,
1983 ca_certs=SIGNING_CA)
1984 self.addCleanup(s.close)
1985 self.assertEqual(0, s.connect_ex(self.server_addr))
1986 self.assertTrue(s.getpeercert())
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00001987
1988 def test_non_blocking_connect_ex(self):
1989 # Issue #11326: non-blocking connect_ex() should allow handshake
1990 # to proceed after the socket gets ready.
Christian Heimesd0486372016-09-10 23:23:33 +02001991 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001992 cert_reqs=ssl.CERT_REQUIRED,
1993 ca_certs=SIGNING_CA,
1994 do_handshake_on_connect=False)
1995 self.addCleanup(s.close)
1996 s.setblocking(False)
1997 rc = s.connect_ex(self.server_addr)
1998 # EWOULDBLOCK under Windows, EINPROGRESS elsewhere
1999 self.assertIn(rc, (0, errno.EINPROGRESS, errno.EWOULDBLOCK))
2000 # Wait for connect to finish
2001 select.select([], [s], [], 5.0)
2002 # Non-blocking handshake
2003 while True:
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002004 try:
Martin Panter3840b2a2016-03-27 01:53:46 +00002005 s.do_handshake()
2006 break
2007 except ssl.SSLWantReadError:
2008 select.select([s], [], [], 5.0)
2009 except ssl.SSLWantWriteError:
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002010 select.select([], [s], [], 5.0)
Martin Panter3840b2a2016-03-27 01:53:46 +00002011 # SSL established
2012 self.assertTrue(s.getpeercert())
Antoine Pitrou40f12ab2012-12-28 19:03:43 +01002013
Antoine Pitrou152efa22010-05-16 18:19:27 +00002014 def test_connect_with_context(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002015 # Same as test_connect, but with a separately created context
Christian Heimes2875c602021-04-19 07:27:10 +02002016 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2017 ctx.check_hostname = False
2018 ctx.verify_mode = ssl.CERT_NONE
Martin Panter3840b2a2016-03-27 01:53:46 +00002019 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2020 s.connect(self.server_addr)
2021 self.assertEqual({}, s.getpeercert())
2022 # Same with a server hostname
2023 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2024 server_hostname="dummy") as s:
2025 s.connect(self.server_addr)
2026 ctx.verify_mode = ssl.CERT_REQUIRED
2027 # This should succeed because we specify the root cert
2028 ctx.load_verify_locations(SIGNING_CA)
2029 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2030 s.connect(self.server_addr)
2031 cert = s.getpeercert()
2032 self.assertTrue(cert)
2033
2034 def test_connect_with_context_fail(self):
2035 # This should fail because we have no verification certs. Connection
2036 # failure crashes ThreadedEchoServer, so run this in an independent
2037 # test method.
Christian Heimes2875c602021-04-19 07:27:10 +02002038 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2039 s = ctx.wrap_socket(
2040 socket.socket(socket.AF_INET),
2041 server_hostname=SIGNED_CERTFILE_HOSTNAME
2042 )
Martin Panter3840b2a2016-03-27 01:53:46 +00002043 self.addCleanup(s.close)
2044 self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
2045 s.connect, self.server_addr)
Antoine Pitrou152efa22010-05-16 18:19:27 +00002046
2047 def test_connect_capath(self):
2048 # Verify server certificates using the `capath` argument
Antoine Pitrou467f28d2010-05-16 19:22:44 +00002049 # NOTE: the subject hashing algorithm has been changed between
2050 # OpenSSL 0.9.8n and 1.0.0, as a result the capath directory must
2051 # contain both versions of each certificate (same content, different
Antoine Pitroud7e4c1c2010-05-17 14:13:10 +00002052 # filename) for this test to be portable across OpenSSL releases.
Christian Heimes2875c602021-04-19 07:27:10 +02002053 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002054 ctx.load_verify_locations(capath=CAPATH)
Christian Heimes2875c602021-04-19 07:27:10 +02002055 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2056 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002057 s.connect(self.server_addr)
2058 cert = s.getpeercert()
2059 self.assertTrue(cert)
Christian Heimes529525f2018-05-23 22:24:45 +02002060
Martin Panter3840b2a2016-03-27 01:53:46 +00002061 # Same with a bytes `capath` argument
Christian Heimes2875c602021-04-19 07:27:10 +02002062 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002063 ctx.load_verify_locations(capath=BYTES_CAPATH)
Christian Heimes2875c602021-04-19 07:27:10 +02002064 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2065 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002066 s.connect(self.server_addr)
2067 cert = s.getpeercert()
2068 self.assertTrue(cert)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002069
Christian Heimesefff7062013-11-21 03:35:02 +01002070 def test_connect_cadata(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002071 with open(SIGNING_CA) as f:
Christian Heimesefff7062013-11-21 03:35:02 +01002072 pem = f.read()
2073 der = ssl.PEM_cert_to_DER_cert(pem)
Christian Heimes2875c602021-04-19 07:27:10 +02002074 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002075 ctx.load_verify_locations(cadata=pem)
Christian Heimes2875c602021-04-19 07:27:10 +02002076 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2077 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002078 s.connect(self.server_addr)
2079 cert = s.getpeercert()
2080 self.assertTrue(cert)
Christian Heimesefff7062013-11-21 03:35:02 +01002081
Martin Panter3840b2a2016-03-27 01:53:46 +00002082 # same with DER
Christian Heimes2875c602021-04-19 07:27:10 +02002083 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002084 ctx.load_verify_locations(cadata=der)
Christian Heimes2875c602021-04-19 07:27:10 +02002085 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2086 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002087 s.connect(self.server_addr)
2088 cert = s.getpeercert()
2089 self.assertTrue(cert)
Christian Heimesefff7062013-11-21 03:35:02 +01002090
Antoine Pitroue3220242010-04-24 11:13:53 +00002091 @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
2092 def test_makefile_close(self):
2093 # Issue #5238: creating a file-like object with makefile() shouldn't
2094 # delay closing the underlying "real socket" (here tested with its
2095 # file descriptor, hence skipping the test under Windows).
Christian Heimesd0486372016-09-10 23:23:33 +02002096 ss = test_wrap_socket(socket.socket(socket.AF_INET))
Martin Panter3840b2a2016-03-27 01:53:46 +00002097 ss.connect(self.server_addr)
2098 fd = ss.fileno()
2099 f = ss.makefile()
2100 f.close()
2101 # The fd is still open
2102 os.read(fd, 0)
2103 # Closing the SSL socket should close the fd too
2104 ss.close()
2105 gc.collect()
2106 with self.assertRaises(OSError) as e:
Antoine Pitroue3220242010-04-24 11:13:53 +00002107 os.read(fd, 0)
Martin Panter3840b2a2016-03-27 01:53:46 +00002108 self.assertEqual(e.exception.errno, errno.EBADF)
Antoine Pitroue3220242010-04-24 11:13:53 +00002109
Antoine Pitrou480a1242010-04-28 21:37:09 +00002110 def test_non_blocking_handshake(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002111 s = socket.socket(socket.AF_INET)
2112 s.connect(self.server_addr)
2113 s.setblocking(False)
Christian Heimesd0486372016-09-10 23:23:33 +02002114 s = test_wrap_socket(s,
Martin Panter3840b2a2016-03-27 01:53:46 +00002115 cert_reqs=ssl.CERT_NONE,
2116 do_handshake_on_connect=False)
2117 self.addCleanup(s.close)
2118 count = 0
2119 while True:
2120 try:
2121 count += 1
2122 s.do_handshake()
2123 break
2124 except ssl.SSLWantReadError:
2125 select.select([s], [], [])
2126 except ssl.SSLWantWriteError:
2127 select.select([], [s], [])
2128 if support.verbose:
2129 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002130
Antoine Pitrou480a1242010-04-28 21:37:09 +00002131 def test_get_server_certificate(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002132 _test_get_server_certificate(self, *self.server_addr, cert=SIGNING_CA)
Antoine Pitrou5aefa662011-04-28 19:24:46 +02002133
juhovh49fdf112021-04-18 21:11:48 +10002134 def test_get_server_certificate_sni(self):
2135 host, port = self.server_addr
2136 server_names = []
2137
2138 # We store servername_cb arguments to make sure they match the host
2139 def servername_cb(ssl_sock, server_name, initial_context):
2140 server_names.append(server_name)
2141 self.server_context.set_servername_callback(servername_cb)
2142
2143 pem = ssl.get_server_certificate((host, port))
2144 if not pem:
2145 self.fail("No server certificate on %s:%s!" % (host, port))
2146
2147 pem = ssl.get_server_certificate((host, port), ca_certs=SIGNING_CA)
2148 if not pem:
2149 self.fail("No server certificate on %s:%s!" % (host, port))
2150 if support.verbose:
2151 sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port, pem))
2152
2153 self.assertEqual(server_names, [host, host])
2154
Martin Panter3840b2a2016-03-27 01:53:46 +00002155 def test_get_server_certificate_fail(self):
2156 # Connection failure crashes ThreadedEchoServer, so run this in an
2157 # independent test method
2158 _test_get_server_certificate_fail(self, *self.server_addr)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002159
Zackery Spytzb2fac1a2021-04-23 22:46:01 -06002160 def test_get_server_certificate_timeout(self):
Christian Heimesf05c2ae2021-04-24 07:54:08 +02002161 def servername_cb(ssl_sock, server_name, initial_context):
2162 time.sleep(0.2)
2163 self.server_context.set_servername_callback(servername_cb)
2164
Zackery Spytzb2fac1a2021-04-23 22:46:01 -06002165 with self.assertRaises(socket.timeout):
2166 ssl.get_server_certificate(self.server_addr, ca_certs=SIGNING_CA,
Christian Heimesf05c2ae2021-04-24 07:54:08 +02002167 timeout=0.1)
Zackery Spytzb2fac1a2021-04-23 22:46:01 -06002168
Antoine Pitrouf4c7bad2010-08-15 23:02:22 +00002169 def test_ciphers(self):
Christian Heimesd0486372016-09-10 23:23:33 +02002170 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002171 cert_reqs=ssl.CERT_NONE, ciphers="ALL") as s:
2172 s.connect(self.server_addr)
Christian Heimesd0486372016-09-10 23:23:33 +02002173 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002174 cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT") as s:
2175 s.connect(self.server_addr)
2176 # Error checking can happen at instantiation or when connecting
2177 with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
2178 with socket.socket(socket.AF_INET) as sock:
Christian Heimesd0486372016-09-10 23:23:33 +02002179 s = test_wrap_socket(sock,
Martin Panter3840b2a2016-03-27 01:53:46 +00002180 cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
2181 s.connect(self.server_addr)
Antoine Pitroufec12ff2010-04-21 19:46:23 +00002182
Christian Heimes9a5395a2013-06-17 15:44:12 +02002183 def test_get_ca_certs_capath(self):
2184 # capath certs are loaded on request
Christian Heimesa170fa12017-09-15 20:27:30 +02002185 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002186 ctx.load_verify_locations(capath=CAPATH)
2187 self.assertEqual(ctx.get_ca_certs(), [])
Christian Heimesa170fa12017-09-15 20:27:30 +02002188 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2189 server_hostname='localhost') as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002190 s.connect(self.server_addr)
2191 cert = s.getpeercert()
2192 self.assertTrue(cert)
2193 self.assertEqual(len(ctx.get_ca_certs()), 1)
Christian Heimes9a5395a2013-06-17 15:44:12 +02002194
Christian Heimes8e7f3942013-12-05 07:41:08 +01002195 def test_context_setget(self):
2196 # Check that the context of a connected socket can be replaced.
Christian Heimesa170fa12017-09-15 20:27:30 +02002197 ctx1 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2198 ctx1.load_verify_locations(capath=CAPATH)
2199 ctx2 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2200 ctx2.load_verify_locations(capath=CAPATH)
Martin Panter3840b2a2016-03-27 01:53:46 +00002201 s = socket.socket(socket.AF_INET)
Christian Heimesa170fa12017-09-15 20:27:30 +02002202 with ctx1.wrap_socket(s, server_hostname='localhost') as ss:
Martin Panter3840b2a2016-03-27 01:53:46 +00002203 ss.connect(self.server_addr)
2204 self.assertIs(ss.context, ctx1)
2205 self.assertIs(ss._sslobj.context, ctx1)
2206 ss.context = ctx2
2207 self.assertIs(ss.context, ctx2)
2208 self.assertIs(ss._sslobj.context, ctx2)
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002209
2210 def ssl_io_loop(self, sock, incoming, outgoing, func, *args, **kwargs):
2211 # A simple IO loop. Call func(*args) depending on the error we get
2212 # (WANT_READ or WANT_WRITE) move data between the socket and the BIOs.
Victor Stinner0d63bac2019-12-11 11:30:03 +01002213 timeout = kwargs.get('timeout', support.SHORT_TIMEOUT)
Victor Stinner50a72af2017-09-11 09:34:24 -07002214 deadline = time.monotonic() + timeout
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002215 count = 0
2216 while True:
Victor Stinner50a72af2017-09-11 09:34:24 -07002217 if time.monotonic() > deadline:
2218 self.fail("timeout")
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002219 errno = None
2220 count += 1
2221 try:
2222 ret = func(*args)
2223 except ssl.SSLError as e:
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002224 if e.errno not in (ssl.SSL_ERROR_WANT_READ,
Martin Panter40b97ec2016-01-14 13:05:46 +00002225 ssl.SSL_ERROR_WANT_WRITE):
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002226 raise
2227 errno = e.errno
2228 # Get any data from the outgoing BIO irrespective of any error, and
2229 # send it to the socket.
2230 buf = outgoing.read()
2231 sock.sendall(buf)
2232 # If there's no error, we're done. For WANT_READ, we need to get
2233 # data from the socket and put it in the incoming BIO.
2234 if errno is None:
2235 break
2236 elif errno == ssl.SSL_ERROR_WANT_READ:
2237 buf = sock.recv(32768)
2238 if buf:
2239 incoming.write(buf)
2240 else:
2241 incoming.write_eof()
2242 if support.verbose:
2243 sys.stdout.write("Needed %d calls to complete %s().\n"
2244 % (count, func.__name__))
2245 return ret
2246
Martin Panter3840b2a2016-03-27 01:53:46 +00002247 def test_bio_handshake(self):
2248 sock = socket.socket(socket.AF_INET)
2249 self.addCleanup(sock.close)
2250 sock.connect(self.server_addr)
2251 incoming = ssl.MemoryBIO()
2252 outgoing = ssl.MemoryBIO()
Christian Heimesa170fa12017-09-15 20:27:30 +02002253 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2254 self.assertTrue(ctx.check_hostname)
2255 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Martin Panter3840b2a2016-03-27 01:53:46 +00002256 ctx.load_verify_locations(SIGNING_CA)
Christian Heimesa170fa12017-09-15 20:27:30 +02002257 sslobj = ctx.wrap_bio(incoming, outgoing, False,
2258 SIGNED_CERTFILE_HOSTNAME)
Martin Panter3840b2a2016-03-27 01:53:46 +00002259 self.assertIs(sslobj._sslobj.owner, sslobj)
2260 self.assertIsNone(sslobj.cipher())
Christian Heimes68771112017-09-05 21:55:40 -07002261 self.assertIsNone(sslobj.version())
Christian Heimes01113fa2016-09-05 23:23:24 +02002262 self.assertIsNotNone(sslobj.shared_ciphers())
Martin Panter3840b2a2016-03-27 01:53:46 +00002263 self.assertRaises(ValueError, sslobj.getpeercert)
2264 if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
2265 self.assertIsNone(sslobj.get_channel_binding('tls-unique'))
2266 self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
2267 self.assertTrue(sslobj.cipher())
Christian Heimes01113fa2016-09-05 23:23:24 +02002268 self.assertIsNotNone(sslobj.shared_ciphers())
Christian Heimes68771112017-09-05 21:55:40 -07002269 self.assertIsNotNone(sslobj.version())
Martin Panter3840b2a2016-03-27 01:53:46 +00002270 self.assertTrue(sslobj.getpeercert())
2271 if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
2272 self.assertTrue(sslobj.get_channel_binding('tls-unique'))
2273 try:
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002274 self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
Martin Panter3840b2a2016-03-27 01:53:46 +00002275 except ssl.SSLSyscallError:
2276 # If the server shuts down the TCP connection without sending a
2277 # secure shutdown message, this is reported as SSL_ERROR_SYSCALL
2278 pass
2279 self.assertRaises(ssl.SSLError, sslobj.write, b'foo')
2280
2281 def test_bio_read_write_data(self):
2282 sock = socket.socket(socket.AF_INET)
2283 self.addCleanup(sock.close)
2284 sock.connect(self.server_addr)
2285 incoming = ssl.MemoryBIO()
2286 outgoing = ssl.MemoryBIO()
Christian Heimes2875c602021-04-19 07:27:10 +02002287 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2288 ctx.check_hostname = False
Martin Panter3840b2a2016-03-27 01:53:46 +00002289 ctx.verify_mode = ssl.CERT_NONE
2290 sslobj = ctx.wrap_bio(incoming, outgoing, False)
2291 self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
2292 req = b'FOO\n'
2293 self.ssl_io_loop(sock, incoming, outgoing, sslobj.write, req)
2294 buf = self.ssl_io_loop(sock, incoming, outgoing, sslobj.read, 1024)
2295 self.assertEqual(buf, b'foo\n')
2296 self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002297
2298
Martin Panter3840b2a2016-03-27 01:53:46 +00002299class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002300
Martin Panter3840b2a2016-03-27 01:53:46 +00002301 def test_timeout_connect_ex(self):
2302 # Issue #12065: on a timeout, connect_ex() should return the original
2303 # errno (mimicking the behaviour of non-SSL sockets).
Serhiy Storchakabfb1cf42020-04-29 10:36:20 +03002304 with socket_helper.transient_internet(REMOTE_HOST):
Christian Heimesd0486372016-09-10 23:23:33 +02002305 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002306 cert_reqs=ssl.CERT_REQUIRED,
2307 do_handshake_on_connect=False)
2308 self.addCleanup(s.close)
2309 s.settimeout(0.0000001)
2310 rc = s.connect_ex((REMOTE_HOST, 443))
2311 if rc == 0:
2312 self.skipTest("REMOTE_HOST responded too quickly")
Carl Meyer29c451c2021-03-27 15:52:28 -06002313 elif rc == errno.ENETUNREACH:
2314 self.skipTest("Network unreachable.")
Martin Panter3840b2a2016-03-27 01:53:46 +00002315 self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK))
2316
Serhiy Storchaka16994912020-04-25 10:06:29 +03002317 @unittest.skipUnless(socket_helper.IPV6_ENABLED, 'Needs IPv6')
Martin Panter3840b2a2016-03-27 01:53:46 +00002318 def test_get_server_certificate_ipv6(self):
Serhiy Storchakabfb1cf42020-04-29 10:36:20 +03002319 with socket_helper.transient_internet('ipv6.google.com'):
Martin Panter3840b2a2016-03-27 01:53:46 +00002320 _test_get_server_certificate(self, 'ipv6.google.com', 443)
2321 _test_get_server_certificate_fail(self, 'ipv6.google.com', 443)
2322
Martin Panter3840b2a2016-03-27 01:53:46 +00002323
2324def _test_get_server_certificate(test, host, port, cert=None):
2325 pem = ssl.get_server_certificate((host, port))
2326 if not pem:
2327 test.fail("No server certificate on %s:%s!" % (host, port))
2328
2329 pem = ssl.get_server_certificate((host, port), ca_certs=cert)
2330 if not pem:
2331 test.fail("No server certificate on %s:%s!" % (host, port))
2332 if support.verbose:
2333 sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem))
2334
2335def _test_get_server_certificate_fail(test, host, port):
2336 try:
2337 pem = ssl.get_server_certificate((host, port), ca_certs=CERTFILE)
2338 except ssl.SSLError as x:
2339 #should fail
2340 if support.verbose:
2341 sys.stdout.write("%s\n" % x)
2342 else:
2343 test.fail("Got server certificate %s for %s:%s!" % (pem, host, port))
2344
2345
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002346from test.ssl_servers import make_https_server
Antoine Pitrou803e6d62010-10-13 10:36:15 +00002347
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002348class ThreadedEchoServer(threading.Thread):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002349
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002350 class ConnectionHandler(threading.Thread):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002351
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002352 """A mildly complicated class, because we want it to work both
2353 with and without the SSL wrapper around the socket connection, so
2354 that we can test the STARTTLS functionality."""
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002355
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002356 def __init__(self, server, connsock, addr):
2357 self.server = server
2358 self.running = False
2359 self.sock = connsock
2360 self.addr = addr
Serhiy Storchaka5eca7f32019-09-01 12:12:52 +03002361 self.sock.setblocking(True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002362 self.sslconn = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002363 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +00002364 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002365
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002366 def wrap_conn(self):
2367 try:
2368 self.sslconn = self.server.context.wrap_socket(
2369 self.sock, server_side=True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002370 self.server.selected_alpn_protocols.append(self.sslconn.selected_alpn_protocol())
Paul Monsonfb7e7502019-05-15 15:38:55 -07002371 except (ConnectionResetError, BrokenPipeError, ConnectionAbortedError) as e:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002372 # We treat ConnectionResetError as though it were an
2373 # SSLError - OpenSSL on Ubuntu abruptly closes the
2374 # connection when asked to use an unsupported protocol.
2375 #
Christian Heimes529525f2018-05-23 22:24:45 +02002376 # BrokenPipeError is raised in TLS 1.3 mode, when OpenSSL
2377 # tries to send session tickets after handshake.
2378 # https://github.com/openssl/openssl/issues/6342
Paul Monsonfb7e7502019-05-15 15:38:55 -07002379 #
2380 # ConnectionAbortedError is raised in TLS 1.3 mode, when OpenSSL
2381 # tries to send session tickets after handshake when using WinSock.
Christian Heimes529525f2018-05-23 22:24:45 +02002382 self.server.conn_errors.append(str(e))
2383 if self.server.chatty:
2384 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
2385 self.running = False
2386 self.close()
2387 return False
2388 except (ssl.SSLError, OSError) as e:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002389 # OSError may occur with wrong protocols, e.g. both
2390 # sides use PROTOCOL_TLS_SERVER.
2391 #
2392 # XXX Various errors can have happened here, for example
2393 # a mismatching protocol version, an invalid certificate,
2394 # or a low-level bug. This should be made more discriminating.
2395 #
2396 # bpo-31323: Store the exception as string to prevent
2397 # a reference leak: server -> conn_errors -> exception
2398 # -> traceback -> self (ConnectionHandler) -> server
2399 self.server.conn_errors.append(str(e))
2400 if self.server.chatty:
2401 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
2402 self.running = False
2403 self.server.stop()
2404 self.close()
2405 return False
2406 else:
2407 self.server.shared_ciphers.append(self.sslconn.shared_ciphers())
2408 if self.server.context.verify_mode == ssl.CERT_REQUIRED:
2409 cert = self.sslconn.getpeercert()
2410 if support.verbose and self.server.chatty:
2411 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
2412 cert_binary = self.sslconn.getpeercert(True)
2413 if support.verbose and self.server.chatty:
Christian Heimesc8666cf2021-04-24 09:17:54 +02002414 if cert_binary is None:
2415 sys.stdout.write(" client did not provide a cert\n")
2416 else:
2417 sys.stdout.write(f" cert binary is {len(cert_binary)}b\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002418 cipher = self.sslconn.cipher()
2419 if support.verbose and self.server.chatty:
2420 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002421 return True
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002422
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002423 def read(self):
2424 if self.sslconn:
2425 return self.sslconn.read()
2426 else:
2427 return self.sock.recv(1024)
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002428
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002429 def write(self, bytes):
2430 if self.sslconn:
2431 return self.sslconn.write(bytes)
2432 else:
2433 return self.sock.send(bytes)
2434
2435 def close(self):
2436 if self.sslconn:
2437 self.sslconn.close()
2438 else:
2439 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002440
Antoine Pitrou480a1242010-04-28 21:37:09 +00002441 def run(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002442 self.running = True
2443 if not self.server.starttls_server:
2444 if not self.wrap_conn():
2445 return
2446 while self.running:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002447 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002448 msg = self.read()
2449 stripped = msg.strip()
2450 if not stripped:
2451 # eof, so quit this handler
2452 self.running = False
2453 try:
2454 self.sock = self.sslconn.unwrap()
2455 except OSError:
2456 # Many tests shut the TCP connection down
2457 # without an SSL shutdown. This causes
2458 # unwrap() to raise OSError with errno=0!
2459 pass
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00002460 else:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002461 self.sslconn = None
2462 self.close()
2463 elif stripped == b'over':
2464 if support.verbose and self.server.connectionchatty:
2465 sys.stdout.write(" server: client closed connection\n")
2466 self.close()
2467 return
2468 elif (self.server.starttls_server and
2469 stripped == b'STARTTLS'):
2470 if support.verbose and self.server.connectionchatty:
2471 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
2472 self.write(b"OK\n")
2473 if not self.wrap_conn():
2474 return
2475 elif (self.server.starttls_server and self.sslconn
2476 and stripped == b'ENDTLS'):
2477 if support.verbose and self.server.connectionchatty:
2478 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
2479 self.write(b"OK\n")
2480 self.sock = self.sslconn.unwrap()
2481 self.sslconn = None
2482 if support.verbose and self.server.connectionchatty:
2483 sys.stdout.write(" server: connection is now unencrypted...\n")
2484 elif stripped == b'CB tls-unique':
2485 if support.verbose and self.server.connectionchatty:
2486 sys.stdout.write(" server: read CB tls-unique from client, sending our CB data...\n")
2487 data = self.sslconn.get_channel_binding("tls-unique")
2488 self.write(repr(data).encode("us-ascii") + b"\n")
Christian Heimes9fb051f2018-09-23 08:32:31 +02002489 elif stripped == b'PHA':
2490 if support.verbose and self.server.connectionchatty:
2491 sys.stdout.write(" server: initiating post handshake auth\n")
2492 try:
2493 self.sslconn.verify_client_post_handshake()
2494 except ssl.SSLError as e:
2495 self.write(repr(e).encode("us-ascii") + b"\n")
2496 else:
2497 self.write(b"OK\n")
2498 elif stripped == b'HASCERT':
2499 if self.sslconn.getpeercert() is not None:
2500 self.write(b'TRUE\n')
2501 else:
2502 self.write(b'FALSE\n')
2503 elif stripped == b'GETCERT':
2504 cert = self.sslconn.getpeercert()
2505 self.write(repr(cert).encode("us-ascii") + b"\n")
Christian Heimes666991f2021-04-26 15:01:40 +02002506 elif stripped == b'VERIFIEDCHAIN':
2507 certs = self.sslconn._sslobj.get_verified_chain()
2508 self.write(len(certs).to_bytes(1, "big") + b"\n")
2509 elif stripped == b'UNVERIFIEDCHAIN':
2510 certs = self.sslconn._sslobj.get_unverified_chain()
2511 self.write(len(certs).to_bytes(1, "big") + b"\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002512 else:
2513 if (support.verbose and
2514 self.server.connectionchatty):
2515 ctype = (self.sslconn and "encrypted") or "unencrypted"
2516 sys.stdout.write(" server: read %r (%s), sending back %r (%s)...\n"
2517 % (msg, ctype, msg.lower(), ctype))
2518 self.write(msg.lower())
Christian Heimesc8666cf2021-04-24 09:17:54 +02002519 except OSError as e:
2520 # handles SSLError and socket errors
Christian Heimes529525f2018-05-23 22:24:45 +02002521 if self.server.chatty and support.verbose:
Christian Heimesc8666cf2021-04-24 09:17:54 +02002522 if isinstance(e, ConnectionError):
2523 # OpenSSL 1.1.1 sometimes raises
2524 # ConnectionResetError when connection is not
2525 # shut down gracefully.
2526 print(
2527 f" Connection reset by peer: {self.addr}"
2528 )
2529 else:
2530 handle_error("Test server failure:\n")
2531 try:
2532 self.write(b"ERROR\n")
2533 except OSError:
2534 pass
Bill Janssen2f5799b2008-06-29 00:08:12 +00002535 self.close()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002536 self.running = False
Christian Heimes529525f2018-05-23 22:24:45 +02002537
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002538 # normally, we'd just stop here, but for the test
2539 # harness, we want to stop the server
2540 self.server.stop()
Bill Janssen54cc54c2007-12-14 22:08:56 +00002541
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002542 def __init__(self, certificate=None, ssl_version=None,
2543 certreqs=None, cacerts=None,
2544 chatty=True, connectionchatty=False, starttls_server=False,
Christian Heimes2875c602021-04-19 07:27:10 +02002545 alpn_protocols=None,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002546 ciphers=None, context=None):
2547 if context:
2548 self.context = context
2549 else:
2550 self.context = ssl.SSLContext(ssl_version
2551 if ssl_version is not None
Christian Heimesa170fa12017-09-15 20:27:30 +02002552 else ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002553 self.context.verify_mode = (certreqs if certreqs is not None
2554 else ssl.CERT_NONE)
2555 if cacerts:
2556 self.context.load_verify_locations(cacerts)
2557 if certificate:
2558 self.context.load_cert_chain(certificate)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002559 if alpn_protocols:
2560 self.context.set_alpn_protocols(alpn_protocols)
2561 if ciphers:
2562 self.context.set_ciphers(ciphers)
2563 self.chatty = chatty
2564 self.connectionchatty = connectionchatty
2565 self.starttls_server = starttls_server
2566 self.sock = socket.socket()
Serhiy Storchaka16994912020-04-25 10:06:29 +03002567 self.port = socket_helper.bind_port(self.sock)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002568 self.flag = None
2569 self.active = False
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002570 self.selected_alpn_protocols = []
2571 self.shared_ciphers = []
2572 self.conn_errors = []
2573 threading.Thread.__init__(self)
2574 self.daemon = True
2575
2576 def __enter__(self):
2577 self.start(threading.Event())
2578 self.flag.wait()
2579 return self
2580
2581 def __exit__(self, *args):
2582 self.stop()
2583 self.join()
2584
2585 def start(self, flag=None):
2586 self.flag = flag
2587 threading.Thread.start(self)
2588
2589 def run(self):
Christian Heimesc715b522021-05-03 17:45:02 +02002590 self.sock.settimeout(1.0)
2591 self.sock.listen(5)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002592 self.active = True
2593 if self.flag:
2594 # signal an event
2595 self.flag.set()
2596 while self.active:
2597 try:
2598 newconn, connaddr = self.sock.accept()
2599 if support.verbose and self.chatty:
2600 sys.stdout.write(' server: new connection from '
2601 + repr(connaddr) + '\n')
2602 handler = self.ConnectionHandler(self, newconn, connaddr)
2603 handler.start()
2604 handler.join()
Christian Heimesc715b522021-05-03 17:45:02 +02002605 except TimeoutError as e:
2606 if support.verbose:
2607 sys.stdout.write(f' connection timeout {e!r}\n')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002608 except KeyboardInterrupt:
2609 self.stop()
Christian Heimes529525f2018-05-23 22:24:45 +02002610 except BaseException as e:
2611 if support.verbose and self.chatty:
2612 sys.stdout.write(
2613 ' connection handling failed: ' + repr(e) + '\n')
2614
Christian Heimesc715b522021-05-03 17:45:02 +02002615 self.close()
2616
2617 def close(self):
2618 if self.sock is not None:
2619 self.sock.close()
2620 self.sock = None
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002621
2622 def stop(self):
2623 self.active = False
2624
2625class AsyncoreEchoServer(threading.Thread):
2626
2627 # this one's based on asyncore.dispatcher
2628
2629 class EchoServer (asyncore.dispatcher):
2630
2631 class ConnectionHandler(asyncore.dispatcher_with_send):
2632
2633 def __init__(self, conn, certfile):
2634 self.socket = test_wrap_socket(conn, server_side=True,
2635 certfile=certfile,
2636 do_handshake_on_connect=False)
2637 asyncore.dispatcher_with_send.__init__(self, self.socket)
2638 self._ssl_accepting = True
2639 self._do_ssl_handshake()
2640
2641 def readable(self):
2642 if isinstance(self.socket, ssl.SSLSocket):
2643 while self.socket.pending() > 0:
2644 self.handle_read_event()
2645 return True
2646
2647 def _do_ssl_handshake(self):
2648 try:
2649 self.socket.do_handshake()
2650 except (ssl.SSLWantReadError, ssl.SSLWantWriteError):
2651 return
2652 except ssl.SSLEOFError:
2653 return self.handle_close()
2654 except ssl.SSLError:
Bill Janssen54cc54c2007-12-14 22:08:56 +00002655 raise
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002656 except OSError as err:
2657 if err.args[0] == errno.ECONNABORTED:
2658 return self.handle_close()
2659 else:
2660 self._ssl_accepting = False
Bill Janssen54cc54c2007-12-14 22:08:56 +00002661
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002662 def handle_read(self):
2663 if self._ssl_accepting:
2664 self._do_ssl_handshake()
2665 else:
2666 data = self.recv(1024)
2667 if support.verbose:
2668 sys.stdout.write(" server: read %s from client\n" % repr(data))
2669 if not data:
2670 self.close()
2671 else:
2672 self.send(data.lower())
Bill Janssen54cc54c2007-12-14 22:08:56 +00002673
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002674 def handle_close(self):
2675 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002676 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002677 sys.stdout.write(" server: closed connection %s\n" % self.socket)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002678
2679 def handle_error(self):
2680 raise
2681
Trent Nelson78520002008-04-10 20:54:35 +00002682 def __init__(self, certfile):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002683 self.certfile = certfile
2684 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Serhiy Storchaka16994912020-04-25 10:06:29 +03002685 self.port = socket_helper.bind_port(sock, '')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002686 asyncore.dispatcher.__init__(self, sock)
2687 self.listen(5)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002688
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002689 def handle_accepted(self, sock_obj, addr):
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002690 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002691 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
2692 self.ConnectionHandler(sock_obj, self.certfile)
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002693
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002694 def handle_error(self):
2695 raise
Bill Janssen54cc54c2007-12-14 22:08:56 +00002696
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002697 def __init__(self, certfile):
2698 self.flag = None
2699 self.active = False
2700 self.server = self.EchoServer(certfile)
2701 self.port = self.server.port
2702 threading.Thread.__init__(self)
2703 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +00002704
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002705 def __str__(self):
2706 return "<%s %s>" % (self.__class__.__name__, self.server)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002707
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002708 def __enter__(self):
2709 self.start(threading.Event())
2710 self.flag.wait()
2711 return self
Thomas Woutersed03b412007-08-28 21:37:11 +00002712
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002713 def __exit__(self, *args):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002714 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002715 sys.stdout.write(" cleanup: stopping server.\n")
2716 self.stop()
2717 if support.verbose:
2718 sys.stdout.write(" cleanup: joining server thread.\n")
2719 self.join()
2720 if support.verbose:
2721 sys.stdout.write(" cleanup: successfully joined.\n")
2722 # make sure that ConnectionHandler is removed from socket_map
2723 asyncore.close_all(ignore_all=True)
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01002724
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002725 def start (self, flag=None):
2726 self.flag = flag
2727 threading.Thread.start(self)
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01002728
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002729 def run(self):
2730 self.active = True
2731 if self.flag:
2732 self.flag.set()
2733 while self.active:
Antoine Pitrou773b5db2010-04-27 08:53:36 +00002734 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002735 asyncore.loop(1)
2736 except:
2737 pass
Trent Nelson6b240cd2008-04-10 20:12:06 +00002738
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002739 def stop(self):
2740 self.active = False
2741 self.server.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002742
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002743def server_params_test(client_context, server_context, indata=b"FOO\n",
2744 chatty=True, connectionchatty=False, sni_name=None,
2745 session=None):
2746 """
2747 Launch a server, connect a client to it and try various reads
2748 and writes.
2749 """
2750 stats = {}
2751 server = ThreadedEchoServer(context=server_context,
2752 chatty=chatty,
2753 connectionchatty=False)
2754 with server:
2755 with client_context.wrap_socket(socket.socket(),
2756 server_hostname=sni_name, session=session) as s:
2757 s.connect((HOST, server.port))
2758 for arg in [indata, bytearray(indata), memoryview(indata)]:
2759 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002760 if support.verbose:
Antoine Pitrou18c913e2010-04-27 10:59:39 +00002761 sys.stdout.write(
Antoine Pitrou480a1242010-04-28 21:37:09 +00002762 " client: sending %r...\n" % indata)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002763 s.write(arg)
Antoine Pitrou18c913e2010-04-27 10:59:39 +00002764 outdata = s.read()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002765 if connectionchatty:
2766 if support.verbose:
2767 sys.stdout.write(" client: read %r\n" % outdata)
Trent Nelson6b240cd2008-04-10 20:12:06 +00002768 if outdata != indata.lower():
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002769 raise AssertionError(
Antoine Pitrou480a1242010-04-28 21:37:09 +00002770 "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
2771 % (outdata[:20], len(outdata),
2772 indata[:20].lower(), len(indata)))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002773 s.write(b"over\n")
2774 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002775 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00002776 sys.stdout.write(" client: closing connection.\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002777 stats.update({
2778 'compression': s.compression(),
2779 'cipher': s.cipher(),
2780 'peercert': s.getpeercert(),
2781 'client_alpn_protocol': s.selected_alpn_protocol(),
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002782 'version': s.version(),
2783 'session_reused': s.session_reused,
2784 'session': s.session,
2785 })
2786 s.close()
2787 stats['server_alpn_protocols'] = server.selected_alpn_protocols
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002788 stats['server_shared_ciphers'] = server.shared_ciphers
2789 return stats
Trent Nelson6b240cd2008-04-10 20:12:06 +00002790
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002791def try_protocol_combo(server_protocol, client_protocol, expect_success,
2792 certsreqs=None, server_options=0, client_options=0):
2793 """
2794 Try to SSL-connect using *client_protocol* to *server_protocol*.
2795 If *expect_success* is true, assert that the connection succeeds,
2796 if it's false, assert that the connection fails.
2797 Also, if *expect_success* is a string, assert that it is the protocol
2798 version actually used by the connection.
2799 """
2800 if certsreqs is None:
2801 certsreqs = ssl.CERT_NONE
2802 certtype = {
2803 ssl.CERT_NONE: "CERT_NONE",
2804 ssl.CERT_OPTIONAL: "CERT_OPTIONAL",
2805 ssl.CERT_REQUIRED: "CERT_REQUIRED",
2806 }[certsreqs]
2807 if support.verbose:
2808 formatstr = (expect_success and " %s->%s %s\n") or " {%s->%s} %s\n"
2809 sys.stdout.write(formatstr %
2810 (ssl.get_protocol_name(client_protocol),
2811 ssl.get_protocol_name(server_protocol),
2812 certtype))
Christian Heimes2875c602021-04-19 07:27:10 +02002813
2814 with warnings_helper.check_warnings():
2815 # ignore Deprecation warnings
2816 client_context = ssl.SSLContext(client_protocol)
2817 client_context.options |= client_options
2818 server_context = ssl.SSLContext(server_protocol)
2819 server_context.options |= server_options
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002820
Victor Stinner3ef63442019-02-19 18:06:03 +01002821 min_version = PROTOCOL_TO_TLS_VERSION.get(client_protocol, None)
2822 if (min_version is not None
Christian Heimes2875c602021-04-19 07:27:10 +02002823 # SSLContext.minimum_version is only available on recent OpenSSL
2824 # (setter added in OpenSSL 1.1.0, getter added in OpenSSL 1.1.1)
2825 and hasattr(server_context, 'minimum_version')
2826 and server_protocol == ssl.PROTOCOL_TLS
2827 and server_context.minimum_version > min_version
2828 ):
Victor Stinner3ef63442019-02-19 18:06:03 +01002829 # If OpenSSL configuration is strict and requires more recent TLS
2830 # version, we have to change the minimum to test old TLS versions.
Christian Heimes2875c602021-04-19 07:27:10 +02002831 with warnings_helper.check_warnings():
2832 server_context.minimum_version = min_version
Victor Stinner3ef63442019-02-19 18:06:03 +01002833
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002834 # NOTE: we must enable "ALL" ciphers on the client, otherwise an
2835 # SSLv23 client will send an SSLv3 hello (rather than SSLv2)
2836 # starting from OpenSSL 1.0.0 (see issue #8322).
Christian Heimesa170fa12017-09-15 20:27:30 +02002837 if client_context.protocol == ssl.PROTOCOL_TLS:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002838 client_context.set_ciphers("ALL")
2839
Christian Heimesf6c6b582021-03-18 23:06:50 +01002840 seclevel_workaround(server_context, client_context)
2841
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002842 for ctx in (client_context, server_context):
2843 ctx.verify_mode = certsreqs
Christian Heimesbd5c7d22018-01-20 15:16:30 +01002844 ctx.load_cert_chain(SIGNED_CERTFILE)
2845 ctx.load_verify_locations(SIGNING_CA)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002846 try:
2847 stats = server_params_test(client_context, server_context,
2848 chatty=False, connectionchatty=False)
2849 # Protocol mismatch can result in either an SSLError, or a
2850 # "Connection reset by peer" error.
2851 except ssl.SSLError:
2852 if expect_success:
2853 raise
2854 except OSError as e:
2855 if expect_success or e.errno != errno.ECONNRESET:
2856 raise
2857 else:
2858 if not expect_success:
2859 raise AssertionError(
2860 "Client protocol %s succeeded with server protocol %s!"
2861 % (ssl.get_protocol_name(client_protocol),
2862 ssl.get_protocol_name(server_protocol)))
2863 elif (expect_success is not True
2864 and expect_success != stats['version']):
2865 raise AssertionError("version mismatch: expected %r, got %r"
2866 % (expect_success, stats['version']))
2867
2868
2869class ThreadedTests(unittest.TestCase):
2870
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002871 def test_echo(self):
2872 """Basic test of an SSL client connecting to a server"""
2873 if support.verbose:
2874 sys.stdout.write("\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002875
Christian Heimesa170fa12017-09-15 20:27:30 +02002876 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002877
2878 with self.subTest(client=ssl.PROTOCOL_TLS_CLIENT, server=ssl.PROTOCOL_TLS_SERVER):
2879 server_params_test(client_context=client_context,
2880 server_context=server_context,
2881 chatty=True, connectionchatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02002882 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002883
2884 client_context.check_hostname = False
2885 with self.subTest(client=ssl.PROTOCOL_TLS_SERVER, server=ssl.PROTOCOL_TLS_CLIENT):
2886 with self.assertRaises(ssl.SSLError) as e:
2887 server_params_test(client_context=server_context,
2888 server_context=client_context,
2889 chatty=True, connectionchatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02002890 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002891 self.assertIn('called a function you should not call',
2892 str(e.exception))
2893
2894 with self.subTest(client=ssl.PROTOCOL_TLS_SERVER, server=ssl.PROTOCOL_TLS_SERVER):
2895 with self.assertRaises(ssl.SSLError) as e:
2896 server_params_test(client_context=server_context,
2897 server_context=server_context,
2898 chatty=True, connectionchatty=True)
2899 self.assertIn('called a function you should not call',
2900 str(e.exception))
2901
2902 with self.subTest(client=ssl.PROTOCOL_TLS_CLIENT, server=ssl.PROTOCOL_TLS_CLIENT):
2903 with self.assertRaises(ssl.SSLError) as e:
2904 server_params_test(client_context=server_context,
2905 server_context=client_context,
2906 chatty=True, connectionchatty=True)
2907 self.assertIn('called a function you should not call',
2908 str(e.exception))
2909
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002910 def test_getpeercert(self):
2911 if support.verbose:
2912 sys.stdout.write("\n")
Christian Heimesa170fa12017-09-15 20:27:30 +02002913
2914 client_context, server_context, hostname = testing_context()
2915 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002916 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002917 with client_context.wrap_socket(socket.socket(),
2918 do_handshake_on_connect=False,
2919 server_hostname=hostname) as s:
2920 s.connect((HOST, server.port))
2921 # getpeercert() raise ValueError while the handshake isn't
2922 # done.
2923 with self.assertRaises(ValueError):
2924 s.getpeercert()
2925 s.do_handshake()
2926 cert = s.getpeercert()
2927 self.assertTrue(cert, "Can't get peer certificate.")
2928 cipher = s.cipher()
2929 if support.verbose:
2930 sys.stdout.write(pprint.pformat(cert) + '\n')
2931 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
2932 if 'subject' not in cert:
2933 self.fail("No subject field in certificate: %s." %
2934 pprint.pformat(cert))
2935 if ((('organizationName', 'Python Software Foundation'),)
2936 not in cert['subject']):
2937 self.fail(
2938 "Missing or invalid 'organizationName' field in certificate subject; "
2939 "should be 'Python Software Foundation'.")
2940 self.assertIn('notBefore', cert)
2941 self.assertIn('notAfter', cert)
2942 before = ssl.cert_time_to_seconds(cert['notBefore'])
2943 after = ssl.cert_time_to_seconds(cert['notAfter'])
2944 self.assertLess(before, after)
Bill Janssen58afe4c2008-09-08 16:45:19 +00002945
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002946 def test_crl_check(self):
2947 if support.verbose:
2948 sys.stdout.write("\n")
2949
Christian Heimesa170fa12017-09-15 20:27:30 +02002950 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002951
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002952 tf = getattr(ssl, "VERIFY_X509_TRUSTED_FIRST", 0)
Christian Heimesa170fa12017-09-15 20:27:30 +02002953 self.assertEqual(client_context.verify_flags, ssl.VERIFY_DEFAULT | tf)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002954
2955 # VERIFY_DEFAULT should pass
2956 server = ThreadedEchoServer(context=server_context, chatty=True)
2957 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002958 with client_context.wrap_socket(socket.socket(),
2959 server_hostname=hostname) as s:
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002960 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002961 cert = s.getpeercert()
2962 self.assertTrue(cert, "Can't get peer certificate.")
Bill Janssen58afe4c2008-09-08 16:45:19 +00002963
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002964 # VERIFY_CRL_CHECK_LEAF without a loaded CRL file fails
Christian Heimesa170fa12017-09-15 20:27:30 +02002965 client_context.verify_flags |= ssl.VERIFY_CRL_CHECK_LEAF
Bill Janssen58afe4c2008-09-08 16:45:19 +00002966
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002967 server = ThreadedEchoServer(context=server_context, chatty=True)
2968 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002969 with client_context.wrap_socket(socket.socket(),
2970 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002971 with self.assertRaisesRegex(ssl.SSLError,
2972 "certificate verify failed"):
2973 s.connect((HOST, server.port))
Bill Janssen58afe4c2008-09-08 16:45:19 +00002974
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002975 # now load a CRL file. The CRL file is signed by the CA.
Christian Heimesa170fa12017-09-15 20:27:30 +02002976 client_context.load_verify_locations(CRLFILE)
Bill Janssen58afe4c2008-09-08 16:45:19 +00002977
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002978 server = ThreadedEchoServer(context=server_context, chatty=True)
2979 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002980 with client_context.wrap_socket(socket.socket(),
2981 server_hostname=hostname) as s:
Antoine Pitroub4bebda2014-04-29 10:03:28 +02002982 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002983 cert = s.getpeercert()
2984 self.assertTrue(cert, "Can't get peer certificate.")
Antoine Pitroub4bebda2014-04-29 10:03:28 +02002985
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002986 def test_check_hostname(self):
2987 if support.verbose:
2988 sys.stdout.write("\n")
Antoine Pitroub4bebda2014-04-29 10:03:28 +02002989
Christian Heimesa170fa12017-09-15 20:27:30 +02002990 client_context, server_context, hostname = testing_context()
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00002991
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002992 # correct hostname should verify
2993 server = ThreadedEchoServer(context=server_context, chatty=True)
2994 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002995 with client_context.wrap_socket(socket.socket(),
2996 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002997 s.connect((HOST, server.port))
2998 cert = s.getpeercert()
2999 self.assertTrue(cert, "Can't get peer certificate.")
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003000
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003001 # incorrect hostname should raise an exception
3002 server = ThreadedEchoServer(context=server_context, chatty=True)
3003 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02003004 with client_context.wrap_socket(socket.socket(),
3005 server_hostname="invalid") as s:
Christian Heimes61d478c2018-01-27 15:51:38 +01003006 with self.assertRaisesRegex(
3007 ssl.CertificateError,
3008 "Hostname mismatch, certificate is not valid for 'invalid'."):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003009 s.connect((HOST, server.port))
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003010
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003011 # missing server_hostname arg should cause an exception, too
3012 server = ThreadedEchoServer(context=server_context, chatty=True)
3013 with server:
3014 with socket.socket() as s:
3015 with self.assertRaisesRegex(ValueError,
3016 "check_hostname requires server_hostname"):
Christian Heimesa170fa12017-09-15 20:27:30 +02003017 client_context.wrap_socket(s)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003018
Christian Heimesb467d9a2021-04-17 10:07:19 +02003019 @unittest.skipUnless(
3020 ssl.HAS_NEVER_CHECK_COMMON_NAME, "test requires hostname_checks_common_name"
3021 )
3022 def test_hostname_checks_common_name(self):
3023 client_context, server_context, hostname = testing_context()
3024 assert client_context.hostname_checks_common_name
3025 client_context.hostname_checks_common_name = False
3026
3027 # default cert has a SAN
3028 server = ThreadedEchoServer(context=server_context, chatty=True)
3029 with server:
3030 with client_context.wrap_socket(socket.socket(),
3031 server_hostname=hostname) as s:
3032 s.connect((HOST, server.port))
3033
3034 client_context, server_context, hostname = testing_context(NOSANFILE)
3035 client_context.hostname_checks_common_name = False
3036 server = ThreadedEchoServer(context=server_context, chatty=True)
3037 with server:
3038 with client_context.wrap_socket(socket.socket(),
3039 server_hostname=hostname) as s:
3040 with self.assertRaises(ssl.SSLCertVerificationError):
3041 s.connect((HOST, server.port))
3042
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003043 def test_ecc_cert(self):
3044 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3045 client_context.load_verify_locations(SIGNING_CA)
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003046 client_context.set_ciphers('ECDHE:ECDSA:!NULL:!aRSA')
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003047 hostname = SIGNED_CERTFILE_ECC_HOSTNAME
3048
3049 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3050 # load ECC cert
3051 server_context.load_cert_chain(SIGNED_CERTFILE_ECC)
3052
3053 # correct hostname should verify
3054 server = ThreadedEchoServer(context=server_context, chatty=True)
3055 with server:
3056 with client_context.wrap_socket(socket.socket(),
3057 server_hostname=hostname) as s:
3058 s.connect((HOST, server.port))
3059 cert = s.getpeercert()
3060 self.assertTrue(cert, "Can't get peer certificate.")
3061 cipher = s.cipher()[0].split('-')
3062 self.assertTrue(cipher[:2], ('ECDHE', 'ECDSA'))
3063
3064 def test_dual_rsa_ecc(self):
3065 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3066 client_context.load_verify_locations(SIGNING_CA)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003067 # TODO: fix TLSv1.3 once SSLContext can restrict signature
3068 # algorithms.
3069 client_context.options |= ssl.OP_NO_TLSv1_3
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003070 # only ECDSA certs
3071 client_context.set_ciphers('ECDHE:ECDSA:!NULL:!aRSA')
3072 hostname = SIGNED_CERTFILE_ECC_HOSTNAME
3073
3074 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3075 # load ECC and RSA key/cert pairs
3076 server_context.load_cert_chain(SIGNED_CERTFILE_ECC)
3077 server_context.load_cert_chain(SIGNED_CERTFILE)
3078
3079 # correct hostname should verify
3080 server = ThreadedEchoServer(context=server_context, chatty=True)
3081 with server:
3082 with client_context.wrap_socket(socket.socket(),
3083 server_hostname=hostname) as s:
3084 s.connect((HOST, server.port))
3085 cert = s.getpeercert()
3086 self.assertTrue(cert, "Can't get peer certificate.")
3087 cipher = s.cipher()[0].split('-')
3088 self.assertTrue(cipher[:2], ('ECDHE', 'ECDSA'))
3089
Christian Heimes66e57422018-01-29 14:25:13 +01003090 def test_check_hostname_idn(self):
3091 if support.verbose:
3092 sys.stdout.write("\n")
3093
Christian Heimes11a14932018-02-24 02:35:08 +01003094 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimes66e57422018-01-29 14:25:13 +01003095 server_context.load_cert_chain(IDNSANSFILE)
3096
Christian Heimes11a14932018-02-24 02:35:08 +01003097 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes66e57422018-01-29 14:25:13 +01003098 context.verify_mode = ssl.CERT_REQUIRED
3099 context.check_hostname = True
3100 context.load_verify_locations(SIGNING_CA)
3101
3102 # correct hostname should verify, when specified in several
3103 # different ways
3104 idn_hostnames = [
3105 ('könig.idn.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003106 'xn--knig-5qa.idn.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003107 ('xn--knig-5qa.idn.pythontest.net',
3108 'xn--knig-5qa.idn.pythontest.net'),
3109 (b'xn--knig-5qa.idn.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003110 'xn--knig-5qa.idn.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003111
3112 ('königsgäßchen.idna2003.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003113 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003114 ('xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
3115 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
3116 (b'xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003117 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
3118
3119 # ('königsgäßchen.idna2008.pythontest.net',
3120 # 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3121 ('xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
3122 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3123 (b'xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
3124 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3125
Christian Heimes66e57422018-01-29 14:25:13 +01003126 ]
3127 for server_hostname, expected_hostname in idn_hostnames:
3128 server = ThreadedEchoServer(context=server_context, chatty=True)
3129 with server:
3130 with context.wrap_socket(socket.socket(),
3131 server_hostname=server_hostname) as s:
3132 self.assertEqual(s.server_hostname, expected_hostname)
3133 s.connect((HOST, server.port))
3134 cert = s.getpeercert()
3135 self.assertEqual(s.server_hostname, expected_hostname)
3136 self.assertTrue(cert, "Can't get peer certificate.")
3137
Christian Heimes66e57422018-01-29 14:25:13 +01003138 # incorrect hostname should raise an exception
3139 server = ThreadedEchoServer(context=server_context, chatty=True)
3140 with server:
3141 with context.wrap_socket(socket.socket(),
3142 server_hostname="python.example.org") as s:
3143 with self.assertRaises(ssl.CertificateError):
3144 s.connect((HOST, server.port))
3145
Christian Heimes529525f2018-05-23 22:24:45 +02003146 def test_wrong_cert_tls12(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003147 """Connecting when the server rejects the client's certificate
3148
3149 Launch a server with CERT_REQUIRED, and check that trying to
3150 connect to it with a wrong client certificate fails.
3151 """
Christian Heimes05d9fe32018-02-27 08:55:39 +01003152 client_context, server_context, hostname = testing_context()
Christian Heimes88bfd0b2018-08-14 12:54:19 +02003153 # load client cert that is not signed by trusted CA
3154 client_context.load_cert_chain(CERTFILE)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003155 # require TLS client authentication
3156 server_context.verify_mode = ssl.CERT_REQUIRED
Christian Heimes529525f2018-05-23 22:24:45 +02003157 # TLS 1.3 has different handshake
3158 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimes05d9fe32018-02-27 08:55:39 +01003159
3160 server = ThreadedEchoServer(
3161 context=server_context, chatty=True, connectionchatty=True,
3162 )
3163
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003164 with server, \
Christian Heimes05d9fe32018-02-27 08:55:39 +01003165 client_context.wrap_socket(socket.socket(),
3166 server_hostname=hostname) as s:
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003167 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003168 # Expect either an SSL error about the server rejecting
3169 # the connection, or a low-level connection reset (which
3170 # sometimes happens on Windows)
3171 s.connect((HOST, server.port))
3172 except ssl.SSLError as e:
3173 if support.verbose:
3174 sys.stdout.write("\nSSLError is %r\n" % e)
3175 except OSError as e:
3176 if e.errno != errno.ECONNRESET:
3177 raise
3178 if support.verbose:
3179 sys.stdout.write("\nsocket.error is %r\n" % e)
3180 else:
3181 self.fail("Use of invalid cert should have failed!")
3182
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003183 @requires_tls_version('TLSv1_3')
Christian Heimes529525f2018-05-23 22:24:45 +02003184 def test_wrong_cert_tls13(self):
3185 client_context, server_context, hostname = testing_context()
Christian Heimes88bfd0b2018-08-14 12:54:19 +02003186 # load client cert that is not signed by trusted CA
3187 client_context.load_cert_chain(CERTFILE)
Christian Heimes529525f2018-05-23 22:24:45 +02003188 server_context.verify_mode = ssl.CERT_REQUIRED
3189 server_context.minimum_version = ssl.TLSVersion.TLSv1_3
3190 client_context.minimum_version = ssl.TLSVersion.TLSv1_3
3191
3192 server = ThreadedEchoServer(
3193 context=server_context, chatty=True, connectionchatty=True,
3194 )
3195 with server, \
3196 client_context.wrap_socket(socket.socket(),
Miss Islington (bot)d2ab15f2021-06-03 13:15:15 -07003197 server_hostname=hostname,
3198 suppress_ragged_eofs=False) as s:
Christian Heimes529525f2018-05-23 22:24:45 +02003199 # TLS 1.3 perform client cert exchange after handshake
3200 s.connect((HOST, server.port))
3201 try:
3202 s.write(b'data')
Christian Heimese0472392021-04-23 20:03:25 +02003203 s.read(1000)
3204 s.write(b'should have failed already')
3205 s.read(1000)
Christian Heimes529525f2018-05-23 22:24:45 +02003206 except ssl.SSLError as e:
3207 if support.verbose:
3208 sys.stdout.write("\nSSLError is %r\n" % e)
3209 except OSError as e:
3210 if e.errno != errno.ECONNRESET:
3211 raise
3212 if support.verbose:
3213 sys.stdout.write("\nsocket.error is %r\n" % e)
3214 else:
Miss Islington (bot)d2ab15f2021-06-03 13:15:15 -07003215 self.fail("Use of invalid cert should have failed!")
Christian Heimes529525f2018-05-23 22:24:45 +02003216
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003217 def test_rude_shutdown(self):
3218 """A brutal shutdown of an SSL server should raise an OSError
3219 in the client when attempting handshake.
3220 """
3221 listener_ready = threading.Event()
3222 listener_gone = threading.Event()
3223
3224 s = socket.socket()
Serhiy Storchaka16994912020-04-25 10:06:29 +03003225 port = socket_helper.bind_port(s, HOST)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003226
3227 # `listener` runs in a thread. It sits in an accept() until
3228 # the main thread connects. Then it rudely closes the socket,
3229 # and sets Event `listener_gone` to let the main thread know
3230 # the socket is gone.
3231 def listener():
3232 s.listen()
3233 listener_ready.set()
3234 newsock, addr = s.accept()
3235 newsock.close()
3236 s.close()
3237 listener_gone.set()
3238
3239 def connector():
3240 listener_ready.wait()
3241 with socket.socket() as c:
3242 c.connect((HOST, port))
3243 listener_gone.wait()
Antoine Pitrou40f08742010-04-24 22:04:40 +00003244 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003245 ssl_sock = test_wrap_socket(c)
3246 except OSError:
3247 pass
3248 else:
3249 self.fail('connecting to closed SSL socket should have failed')
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003250
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003251 t = threading.Thread(target=listener)
3252 t.start()
3253 try:
3254 connector()
3255 finally:
Antoine Pitrou5c89b4e2012-11-11 01:25:36 +01003256 t.join()
Antoine Pitrou5c89b4e2012-11-11 01:25:36 +01003257
Christian Heimesb3ad0e52017-09-08 12:00:19 -07003258 def test_ssl_cert_verify_error(self):
3259 if support.verbose:
3260 sys.stdout.write("\n")
3261
3262 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3263 server_context.load_cert_chain(SIGNED_CERTFILE)
3264
3265 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3266
3267 server = ThreadedEchoServer(context=server_context, chatty=True)
3268 with server:
3269 with context.wrap_socket(socket.socket(),
Christian Heimesa170fa12017-09-15 20:27:30 +02003270 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Christian Heimesb3ad0e52017-09-08 12:00:19 -07003271 try:
3272 s.connect((HOST, server.port))
3273 except ssl.SSLError as e:
3274 msg = 'unable to get local issuer certificate'
3275 self.assertIsInstance(e, ssl.SSLCertVerificationError)
3276 self.assertEqual(e.verify_code, 20)
3277 self.assertEqual(e.verify_message, msg)
3278 self.assertIn(msg, repr(e))
3279 self.assertIn('certificate verify failed', repr(e))
3280
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003281 @requires_tls_version('SSLv2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003282 def test_protocol_sslv2(self):
3283 """Connecting to an SSLv2 server with various client options"""
3284 if support.verbose:
3285 sys.stdout.write("\n")
3286 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
3287 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
3288 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
Christian Heimesa170fa12017-09-15 20:27:30 +02003289 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003290 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003291 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
3292 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
3293 # SSLv23 client with specific SSL options
Christian Heimesa170fa12017-09-15 20:27:30 +02003294 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003295 client_options=ssl.OP_NO_SSLv3)
Christian Heimesa170fa12017-09-15 20:27:30 +02003296 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003297 client_options=ssl.OP_NO_TLSv1)
Antoine Pitrou242db722013-05-01 20:52:07 +02003298
Christian Heimesa170fa12017-09-15 20:27:30 +02003299 def test_PROTOCOL_TLS(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003300 """Connecting to an SSLv23 server with various client options"""
3301 if support.verbose:
3302 sys.stdout.write("\n")
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003303 if has_tls_version('SSLv2'):
Antoine Pitrou8f85f902012-01-03 22:46:48 +01003304 try:
Christian Heimesa170fa12017-09-15 20:27:30 +02003305 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv2, True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003306 except OSError as x:
3307 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
3308 if support.verbose:
3309 sys.stdout.write(
3310 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
3311 % str(x))
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003312 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003313 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False)
3314 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003315 if has_tls_version('TLSv1'):
3316 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1')
Antoine Pitrou8f85f902012-01-03 22:46:48 +01003317
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003318 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003319 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False, ssl.CERT_OPTIONAL)
3320 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True, ssl.CERT_OPTIONAL)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003321 if has_tls_version('TLSv1'):
3322 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003323
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003324 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003325 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False, ssl.CERT_REQUIRED)
3326 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True, ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003327 if has_tls_version('TLSv1'):
3328 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003329
3330 # Server with specific SSL options
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003331 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003332 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003333 server_options=ssl.OP_NO_SSLv3)
3334 # Will choose TLSv1
Christian Heimesa170fa12017-09-15 20:27:30 +02003335 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003336 server_options=ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003337 if has_tls_version('TLSv1'):
3338 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, False,
3339 server_options=ssl.OP_NO_TLSv1)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003340
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003341 @requires_tls_version('SSLv3')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003342 def test_protocol_sslv3(self):
3343 """Connecting to an SSLv3 server with various client options"""
3344 if support.verbose:
3345 sys.stdout.write("\n")
3346 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3')
3347 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_OPTIONAL)
3348 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003349 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003350 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003351 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003352 client_options=ssl.OP_NO_SSLv3)
3353 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003354
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003355 @requires_tls_version('TLSv1')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003356 def test_protocol_tlsv1(self):
3357 """Connecting to a TLSv1 server with various client options"""
3358 if support.verbose:
3359 sys.stdout.write("\n")
3360 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1')
3361 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL)
3362 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003363 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003364 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003365 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003366 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003367 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003368 client_options=ssl.OP_NO_TLSv1)
3369
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003370 @requires_tls_version('TLSv1_1')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003371 def test_protocol_tlsv1_1(self):
3372 """Connecting to a TLSv1.1 server with various client options.
3373 Testing against older TLS versions."""
3374 if support.verbose:
3375 sys.stdout.write("\n")
3376 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1')
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003377 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003378 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003379 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003380 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003381 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003382 client_options=ssl.OP_NO_TLSv1_1)
3383
Christian Heimesa170fa12017-09-15 20:27:30 +02003384 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1')
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003385 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False)
3386 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003387
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003388 @requires_tls_version('TLSv1_2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003389 def test_protocol_tlsv1_2(self):
3390 """Connecting to a TLSv1.2 server with various client options.
3391 Testing against older TLS versions."""
3392 if support.verbose:
3393 sys.stdout.write("\n")
3394 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2',
3395 server_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,
3396 client_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003397 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003398 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003399 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003400 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003401 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003402 client_options=ssl.OP_NO_TLSv1_2)
3403
Christian Heimesa170fa12017-09-15 20:27:30 +02003404 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003405 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1, False)
3406 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_2, False)
3407 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False)
3408 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False)
3409
3410 def test_starttls(self):
3411 """Switching from clear text to encrypted and back again."""
3412 msgs = (b"msg 1", b"MSG 2", b"STARTTLS", b"MSG 3", b"msg 4", b"ENDTLS", b"msg 5", b"msg 6")
3413
3414 server = ThreadedEchoServer(CERTFILE,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003415 starttls_server=True,
3416 chatty=True,
3417 connectionchatty=True)
3418 wrapped = False
3419 with server:
3420 s = socket.socket()
Serhiy Storchaka5eca7f32019-09-01 12:12:52 +03003421 s.setblocking(True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003422 s.connect((HOST, server.port))
Antoine Pitroud6494802011-07-21 01:11:30 +02003423 if support.verbose:
3424 sys.stdout.write("\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003425 for indata in msgs:
Antoine Pitroud6494802011-07-21 01:11:30 +02003426 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003427 sys.stdout.write(
3428 " client: sending %r...\n" % indata)
3429 if wrapped:
3430 conn.write(indata)
3431 outdata = conn.read()
3432 else:
3433 s.send(indata)
3434 outdata = s.recv(1024)
3435 msg = outdata.strip().lower()
3436 if indata == b"STARTTLS" and msg.startswith(b"ok"):
3437 # STARTTLS ok, switch to secure mode
3438 if support.verbose:
3439 sys.stdout.write(
3440 " client: read %r from server, starting TLS...\n"
3441 % msg)
Christian Heimesa170fa12017-09-15 20:27:30 +02003442 conn = test_wrap_socket(s)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003443 wrapped = True
3444 elif indata == b"ENDTLS" and msg.startswith(b"ok"):
3445 # ENDTLS ok, switch back to clear text
3446 if support.verbose:
3447 sys.stdout.write(
3448 " client: read %r from server, ending TLS...\n"
3449 % msg)
3450 s = conn.unwrap()
3451 wrapped = False
3452 else:
3453 if support.verbose:
3454 sys.stdout.write(
3455 " client: read %r from server\n" % msg)
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003456 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003457 sys.stdout.write(" client: closing connection.\n")
3458 if wrapped:
3459 conn.write(b"over\n")
3460 else:
3461 s.send(b"over\n")
3462 if wrapped:
3463 conn.close()
3464 else:
3465 s.close()
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003466
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003467 def test_socketserver(self):
3468 """Using socketserver to create and manage SSL connections."""
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003469 server = make_https_server(self, certfile=SIGNED_CERTFILE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003470 # try to connect
3471 if support.verbose:
3472 sys.stdout.write('\n')
3473 with open(CERTFILE, 'rb') as f:
3474 d1 = f.read()
3475 d2 = ''
3476 # now fetch the same data from the HTTPS server
3477 url = 'https://localhost:%d/%s' % (
3478 server.port, os.path.split(CERTFILE)[1])
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003479 context = ssl.create_default_context(cafile=SIGNING_CA)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003480 f = urllib.request.urlopen(url, context=context)
3481 try:
3482 dlen = f.info().get("content-length")
3483 if dlen and (int(dlen) > 0):
3484 d2 = f.read(int(dlen))
3485 if support.verbose:
3486 sys.stdout.write(
3487 " client: read %d bytes from remote server '%s'\n"
3488 % (len(d2), server))
3489 finally:
3490 f.close()
3491 self.assertEqual(d1, d2)
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003492
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003493 def test_asyncore_server(self):
3494 """Check the example asyncore integration."""
3495 if support.verbose:
3496 sys.stdout.write("\n")
Antoine Pitrou0e576f12011-12-22 10:03:38 +01003497
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003498 indata = b"FOO\n"
3499 server = AsyncoreEchoServer(CERTFILE)
3500 with server:
3501 s = test_wrap_socket(socket.socket())
3502 s.connect(('127.0.0.1', server.port))
3503 if support.verbose:
3504 sys.stdout.write(
3505 " client: sending %r...\n" % indata)
3506 s.write(indata)
3507 outdata = s.read()
3508 if support.verbose:
3509 sys.stdout.write(" client: read %r\n" % outdata)
3510 if outdata != indata.lower():
3511 self.fail(
3512 "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
3513 % (outdata[:20], len(outdata),
3514 indata[:20].lower(), len(indata)))
3515 s.write(b"over\n")
3516 if support.verbose:
3517 sys.stdout.write(" client: closing connection.\n")
3518 s.close()
3519 if support.verbose:
3520 sys.stdout.write(" client: connection closed.\n")
Benjamin Petersoncca27322015-01-23 16:35:37 -05003521
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003522 def test_recv_send(self):
3523 """Test recv(), send() and friends."""
3524 if support.verbose:
3525 sys.stdout.write("\n")
3526
3527 server = ThreadedEchoServer(CERTFILE,
3528 certreqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003529 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003530 cacerts=CERTFILE,
3531 chatty=True,
3532 connectionchatty=False)
3533 with server:
3534 s = test_wrap_socket(socket.socket(),
3535 server_side=False,
3536 certfile=CERTFILE,
3537 ca_certs=CERTFILE,
Christian Heimes2875c602021-04-19 07:27:10 +02003538 cert_reqs=ssl.CERT_NONE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003539 s.connect((HOST, server.port))
3540 # helper methods for standardising recv* method signatures
3541 def _recv_into():
3542 b = bytearray(b"\0"*100)
3543 count = s.recv_into(b)
3544 return b[:count]
3545
3546 def _recvfrom_into():
3547 b = bytearray(b"\0"*100)
3548 count, addr = s.recvfrom_into(b)
3549 return b[:count]
3550
3551 # (name, method, expect success?, *args, return value func)
3552 send_methods = [
3553 ('send', s.send, True, [], len),
3554 ('sendto', s.sendto, False, ["some.address"], len),
3555 ('sendall', s.sendall, True, [], lambda x: None),
3556 ]
3557 # (name, method, whether to expect success, *args)
3558 recv_methods = [
3559 ('recv', s.recv, True, []),
3560 ('recvfrom', s.recvfrom, False, ["some.address"]),
3561 ('recv_into', _recv_into, True, []),
3562 ('recvfrom_into', _recvfrom_into, False, []),
3563 ]
3564 data_prefix = "PREFIX_"
3565
3566 for (meth_name, send_meth, expect_success, args,
3567 ret_val_meth) in send_methods:
3568 indata = (data_prefix + meth_name).encode('ascii')
3569 try:
3570 ret = send_meth(indata, *args)
3571 msg = "sending with {}".format(meth_name)
3572 self.assertEqual(ret, ret_val_meth(indata), msg=msg)
3573 outdata = s.read()
3574 if outdata != indata.lower():
3575 self.fail(
3576 "While sending with <<{name:s}>> bad data "
3577 "<<{outdata:r}>> ({nout:d}) received; "
3578 "expected <<{indata:r}>> ({nin:d})\n".format(
3579 name=meth_name, outdata=outdata[:20],
3580 nout=len(outdata),
3581 indata=indata[:20], nin=len(indata)
3582 )
3583 )
3584 except ValueError as e:
3585 if expect_success:
3586 self.fail(
3587 "Failed to send with method <<{name:s}>>; "
3588 "expected to succeed.\n".format(name=meth_name)
3589 )
3590 if not str(e).startswith(meth_name):
3591 self.fail(
3592 "Method <<{name:s}>> failed with unexpected "
3593 "exception message: {exp:s}\n".format(
3594 name=meth_name, exp=e
3595 )
3596 )
3597
3598 for meth_name, recv_meth, expect_success, args in recv_methods:
3599 indata = (data_prefix + meth_name).encode('ascii')
3600 try:
3601 s.send(indata)
3602 outdata = recv_meth(*args)
3603 if outdata != indata.lower():
3604 self.fail(
3605 "While receiving with <<{name:s}>> bad data "
3606 "<<{outdata:r}>> ({nout:d}) received; "
3607 "expected <<{indata:r}>> ({nin:d})\n".format(
3608 name=meth_name, outdata=outdata[:20],
3609 nout=len(outdata),
3610 indata=indata[:20], nin=len(indata)
3611 )
3612 )
3613 except ValueError as e:
3614 if expect_success:
3615 self.fail(
3616 "Failed to receive with method <<{name:s}>>; "
3617 "expected to succeed.\n".format(name=meth_name)
3618 )
3619 if not str(e).startswith(meth_name):
3620 self.fail(
3621 "Method <<{name:s}>> failed with unexpected "
3622 "exception message: {exp:s}\n".format(
3623 name=meth_name, exp=e
3624 )
3625 )
3626 # consume data
3627 s.read()
3628
3629 # read(-1, buffer) is supported, even though read(-1) is not
3630 data = b"data"
3631 s.send(data)
3632 buffer = bytearray(len(data))
3633 self.assertEqual(s.read(-1, buffer), len(data))
3634 self.assertEqual(buffer, data)
3635
Christian Heimes888bbdc2017-09-07 14:18:21 -07003636 # sendall accepts bytes-like objects
3637 if ctypes is not None:
3638 ubyte = ctypes.c_ubyte * len(data)
3639 byteslike = ubyte.from_buffer_copy(data)
3640 s.sendall(byteslike)
3641 self.assertEqual(s.read(), data)
3642
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003643 # Make sure sendmsg et al are disallowed to avoid
3644 # inadvertent disclosure of data and/or corruption
3645 # of the encrypted data stream
Serhiy Storchaka42b1d612018-12-06 22:36:55 +02003646 self.assertRaises(NotImplementedError, s.dup)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003647 self.assertRaises(NotImplementedError, s.sendmsg, [b"data"])
3648 self.assertRaises(NotImplementedError, s.recvmsg, 100)
3649 self.assertRaises(NotImplementedError,
Serhiy Storchaka42b1d612018-12-06 22:36:55 +02003650 s.recvmsg_into, [bytearray(100)])
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003651 s.write(b"over\n")
3652
3653 self.assertRaises(ValueError, s.recv, -1)
3654 self.assertRaises(ValueError, s.read, -1)
3655
3656 s.close()
3657
3658 def test_recv_zero(self):
3659 server = ThreadedEchoServer(CERTFILE)
3660 server.__enter__()
3661 self.addCleanup(server.__exit__, None, None)
3662 s = socket.create_connection((HOST, server.port))
3663 self.addCleanup(s.close)
3664 s = test_wrap_socket(s, suppress_ragged_eofs=False)
3665 self.addCleanup(s.close)
3666
3667 # recv/read(0) should return no data
3668 s.send(b"data")
3669 self.assertEqual(s.recv(0), b"")
3670 self.assertEqual(s.read(0), b"")
3671 self.assertEqual(s.read(), b"data")
3672
3673 # Should not block if the other end sends no data
3674 s.setblocking(False)
3675 self.assertEqual(s.recv(0), b"")
3676 self.assertEqual(s.recv_into(bytearray()), 0)
3677
3678 def test_nonblocking_send(self):
3679 server = ThreadedEchoServer(CERTFILE,
3680 certreqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003681 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003682 cacerts=CERTFILE,
3683 chatty=True,
3684 connectionchatty=False)
3685 with server:
3686 s = test_wrap_socket(socket.socket(),
3687 server_side=False,
3688 certfile=CERTFILE,
3689 ca_certs=CERTFILE,
Christian Heimes2875c602021-04-19 07:27:10 +02003690 cert_reqs=ssl.CERT_NONE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003691 s.connect((HOST, server.port))
3692 s.setblocking(False)
3693
3694 # If we keep sending data, at some point the buffers
3695 # will be full and the call will block
3696 buf = bytearray(8192)
3697 def fill_buffer():
3698 while True:
3699 s.send(buf)
3700 self.assertRaises((ssl.SSLWantWriteError,
3701 ssl.SSLWantReadError), fill_buffer)
3702
3703 # Now read all the output and discard it
3704 s.setblocking(True)
3705 s.close()
3706
3707 def test_handshake_timeout(self):
3708 # Issue #5103: SSL handshake must respect the socket timeout
3709 server = socket.socket(socket.AF_INET)
3710 host = "127.0.0.1"
Serhiy Storchaka16994912020-04-25 10:06:29 +03003711 port = socket_helper.bind_port(server)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003712 started = threading.Event()
3713 finish = False
3714
3715 def serve():
3716 server.listen()
3717 started.set()
3718 conns = []
3719 while not finish:
3720 r, w, e = select.select([server], [], [], 0.1)
3721 if server in r:
3722 # Let the socket hang around rather than having
3723 # it closed by garbage collection.
3724 conns.append(server.accept()[0])
3725 for sock in conns:
3726 sock.close()
3727
3728 t = threading.Thread(target=serve)
3729 t.start()
3730 started.wait()
3731
3732 try:
3733 try:
3734 c = socket.socket(socket.AF_INET)
3735 c.settimeout(0.2)
3736 c.connect((host, port))
3737 # Will attempt handshake and time out
Christian Heimes03c8ddd2020-11-20 09:26:07 +01003738 self.assertRaisesRegex(TimeoutError, "timed out",
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003739 test_wrap_socket, c)
3740 finally:
3741 c.close()
3742 try:
3743 c = socket.socket(socket.AF_INET)
3744 c = test_wrap_socket(c)
3745 c.settimeout(0.2)
3746 # Will attempt handshake and time out
Christian Heimes03c8ddd2020-11-20 09:26:07 +01003747 self.assertRaisesRegex(TimeoutError, "timed out",
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003748 c.connect, (host, port))
3749 finally:
3750 c.close()
3751 finally:
3752 finish = True
3753 t.join()
3754 server.close()
3755
3756 def test_server_accept(self):
3757 # Issue #16357: accept() on a SSLSocket created through
3758 # SSLContext.wrap_socket().
Christian Heimes2875c602021-04-19 07:27:10 +02003759 client_ctx, server_ctx, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003760 server = socket.socket(socket.AF_INET)
3761 host = "127.0.0.1"
Serhiy Storchaka16994912020-04-25 10:06:29 +03003762 port = socket_helper.bind_port(server)
Christian Heimes2875c602021-04-19 07:27:10 +02003763 server = server_ctx.wrap_socket(server, server_side=True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003764 self.assertTrue(server.server_side)
3765
3766 evt = threading.Event()
3767 remote = None
3768 peer = None
3769 def serve():
3770 nonlocal remote, peer
3771 server.listen()
3772 # Block on the accept and wait on the connection to close.
3773 evt.set()
3774 remote, peer = server.accept()
Christian Heimes529525f2018-05-23 22:24:45 +02003775 remote.send(remote.recv(4))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003776
3777 t = threading.Thread(target=serve)
3778 t.start()
3779 # Client wait until server setup and perform a connect.
3780 evt.wait()
Christian Heimes2875c602021-04-19 07:27:10 +02003781 client = client_ctx.wrap_socket(
3782 socket.socket(), server_hostname=hostname
3783 )
3784 client.connect((hostname, port))
Christian Heimes529525f2018-05-23 22:24:45 +02003785 client.send(b'data')
3786 client.recv()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003787 client_addr = client.getsockname()
3788 client.close()
3789 t.join()
3790 remote.close()
3791 server.close()
3792 # Sanity checks.
3793 self.assertIsInstance(remote, ssl.SSLSocket)
3794 self.assertEqual(peer, client_addr)
3795
3796 def test_getpeercert_enotconn(self):
Christian Heimes2875c602021-04-19 07:27:10 +02003797 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3798 context.check_hostname = False
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003799 with context.wrap_socket(socket.socket()) as sock:
3800 with self.assertRaises(OSError) as cm:
3801 sock.getpeercert()
3802 self.assertEqual(cm.exception.errno, errno.ENOTCONN)
3803
3804 def test_do_handshake_enotconn(self):
Christian Heimes2875c602021-04-19 07:27:10 +02003805 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3806 context.check_hostname = False
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003807 with context.wrap_socket(socket.socket()) as sock:
3808 with self.assertRaises(OSError) as cm:
3809 sock.do_handshake()
3810 self.assertEqual(cm.exception.errno, errno.ENOTCONN)
3811
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003812 def test_no_shared_ciphers(self):
3813 client_context, server_context, hostname = testing_context()
3814 # OpenSSL enables all TLS 1.3 ciphers, enforce TLS 1.2 for test
3815 client_context.options |= ssl.OP_NO_TLSv1_3
Victor Stinner5e922652018-09-07 17:30:33 +02003816 # Force different suites on client and server
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003817 client_context.set_ciphers("AES128")
3818 server_context.set_ciphers("AES256")
3819 with ThreadedEchoServer(context=server_context) as server:
3820 with client_context.wrap_socket(socket.socket(),
3821 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003822 with self.assertRaises(OSError):
3823 s.connect((HOST, server.port))
3824 self.assertIn("no shared cipher", server.conn_errors[0])
3825
3826 def test_version_basic(self):
3827 """
3828 Basic tests for SSLSocket.version().
3829 More tests are done in the test_protocol_*() methods.
3830 """
Christian Heimesa170fa12017-09-15 20:27:30 +02003831 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3832 context.check_hostname = False
3833 context.verify_mode = ssl.CERT_NONE
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003834 with ThreadedEchoServer(CERTFILE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003835 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003836 chatty=False) as server:
3837 with context.wrap_socket(socket.socket()) as s:
3838 self.assertIs(s.version(), None)
Christian Heimes141c5e82018-02-24 21:10:57 +01003839 self.assertIs(s._sslobj, None)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003840 s.connect((HOST, server.port))
Christian Heimes39258d32021-04-17 11:36:35 +02003841 self.assertEqual(s.version(), 'TLSv1.3')
Christian Heimes141c5e82018-02-24 21:10:57 +01003842 self.assertIs(s._sslobj, None)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003843 self.assertIs(s.version(), None)
3844
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003845 @requires_tls_version('TLSv1_3')
Christian Heimescb5b68a2017-09-07 18:07:00 -07003846 def test_tls1_3(self):
Christian Heimes2875c602021-04-19 07:27:10 +02003847 client_context, server_context, hostname = testing_context()
3848 client_context.minimum_version = ssl.TLSVersion.TLSv1_3
3849 with ThreadedEchoServer(context=server_context) as server:
3850 with client_context.wrap_socket(socket.socket(),
3851 server_hostname=hostname) as s:
Christian Heimescb5b68a2017-09-07 18:07:00 -07003852 s.connect((HOST, server.port))
Christian Heimes05d9fe32018-02-27 08:55:39 +01003853 self.assertIn(s.cipher()[0], {
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003854 'TLS_AES_256_GCM_SHA384',
3855 'TLS_CHACHA20_POLY1305_SHA256',
3856 'TLS_AES_128_GCM_SHA256',
Christian Heimes05d9fe32018-02-27 08:55:39 +01003857 })
3858 self.assertEqual(s.version(), 'TLSv1.3')
Christian Heimescb5b68a2017-09-07 18:07:00 -07003859
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003860 @requires_tls_version('TLSv1_2')
Christian Heimes2875c602021-04-19 07:27:10 +02003861 @requires_tls_version('TLSv1')
3862 @ignore_deprecation
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003863 def test_min_max_version_tlsv1_2(self):
Christian Heimes698dde12018-02-27 11:54:43 +01003864 client_context, server_context, hostname = testing_context()
3865 # client TLSv1.0 to 1.2
3866 client_context.minimum_version = ssl.TLSVersion.TLSv1
3867 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
3868 # server only TLSv1.2
3869 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
3870 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
3871
3872 with ThreadedEchoServer(context=server_context) as server:
3873 with client_context.wrap_socket(socket.socket(),
3874 server_hostname=hostname) as s:
3875 s.connect((HOST, server.port))
3876 self.assertEqual(s.version(), 'TLSv1.2')
3877
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003878 @requires_tls_version('TLSv1_1')
Christian Heimes2875c602021-04-19 07:27:10 +02003879 @ignore_deprecation
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003880 def test_min_max_version_tlsv1_1(self):
3881 client_context, server_context, hostname = testing_context()
Christian Heimes698dde12018-02-27 11:54:43 +01003882 # client 1.0 to 1.2, server 1.0 to 1.1
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003883 client_context.minimum_version = ssl.TLSVersion.TLSv1
3884 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimes698dde12018-02-27 11:54:43 +01003885 server_context.minimum_version = ssl.TLSVersion.TLSv1
3886 server_context.maximum_version = ssl.TLSVersion.TLSv1_1
Christian Heimesf6c6b582021-03-18 23:06:50 +01003887 seclevel_workaround(client_context, server_context)
Christian Heimes698dde12018-02-27 11:54:43 +01003888
3889 with ThreadedEchoServer(context=server_context) as server:
3890 with client_context.wrap_socket(socket.socket(),
3891 server_hostname=hostname) as s:
3892 s.connect((HOST, server.port))
3893 self.assertEqual(s.version(), 'TLSv1.1')
3894
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003895 @requires_tls_version('TLSv1_2')
Christian Heimesce04e712020-11-18 13:10:53 +01003896 @requires_tls_version('TLSv1')
Christian Heimes2875c602021-04-19 07:27:10 +02003897 @ignore_deprecation
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003898 def test_min_max_version_mismatch(self):
3899 client_context, server_context, hostname = testing_context()
Christian Heimes698dde12018-02-27 11:54:43 +01003900 # client 1.0, server 1.2 (mismatch)
Christian Heimes698dde12018-02-27 11:54:43 +01003901 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesc9bc49c2019-09-11 19:24:47 +02003902 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
Christian Heimese35d1ba2019-06-03 20:40:15 +02003903 client_context.maximum_version = ssl.TLSVersion.TLSv1
Christian Heimesde606ea2019-09-11 19:48:58 +02003904 client_context.minimum_version = ssl.TLSVersion.TLSv1
Christian Heimesf6c6b582021-03-18 23:06:50 +01003905 seclevel_workaround(client_context, server_context)
3906
Christian Heimes698dde12018-02-27 11:54:43 +01003907 with ThreadedEchoServer(context=server_context) as server:
3908 with client_context.wrap_socket(socket.socket(),
3909 server_hostname=hostname) as s:
3910 with self.assertRaises(ssl.SSLError) as e:
3911 s.connect((HOST, server.port))
3912 self.assertIn("alert", str(e.exception))
3913
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003914 @requires_tls_version('SSLv3')
Christian Heimes698dde12018-02-27 11:54:43 +01003915 def test_min_max_version_sslv3(self):
3916 client_context, server_context, hostname = testing_context()
3917 server_context.minimum_version = ssl.TLSVersion.SSLv3
3918 client_context.minimum_version = ssl.TLSVersion.SSLv3
3919 client_context.maximum_version = ssl.TLSVersion.SSLv3
Christian Heimesf6c6b582021-03-18 23:06:50 +01003920 seclevel_workaround(client_context, server_context)
3921
Christian Heimes698dde12018-02-27 11:54:43 +01003922 with ThreadedEchoServer(context=server_context) as server:
3923 with client_context.wrap_socket(socket.socket(),
3924 server_hostname=hostname) as s:
3925 s.connect((HOST, server.port))
3926 self.assertEqual(s.version(), 'SSLv3')
3927
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003928 def test_default_ecdh_curve(self):
3929 # Issue #21015: elliptic curve-based Diffie Hellman key exchange
3930 # should be enabled by default on SSL contexts.
Christian Heimes2875c602021-04-19 07:27:10 +02003931 client_context, server_context, hostname = testing_context()
Christian Heimescb5b68a2017-09-07 18:07:00 -07003932 # TLSv1.3 defaults to PFS key agreement and no longer has KEA in
3933 # cipher name.
Christian Heimes2875c602021-04-19 07:27:10 +02003934 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003935 # Prior to OpenSSL 1.0.0, ECDH ciphers have to be enabled
3936 # explicitly using the 'ECCdraft' cipher alias. Otherwise,
3937 # our default cipher list should prefer ECDH-based ciphers
3938 # automatically.
Christian Heimes2875c602021-04-19 07:27:10 +02003939 with ThreadedEchoServer(context=server_context) as server:
3940 with client_context.wrap_socket(socket.socket(),
3941 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003942 s.connect((HOST, server.port))
3943 self.assertIn("ECDH", s.cipher()[0])
3944
3945 @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES,
3946 "'tls-unique' channel binding not available")
3947 def test_tls_unique_channel_binding(self):
3948 """Test tls-unique channel binding."""
3949 if support.verbose:
3950 sys.stdout.write("\n")
3951
Christian Heimes05d9fe32018-02-27 08:55:39 +01003952 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01003953
3954 server = ThreadedEchoServer(context=server_context,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003955 chatty=True,
3956 connectionchatty=False)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003957
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003958 with server:
Christian Heimes05d9fe32018-02-27 08:55:39 +01003959 with client_context.wrap_socket(
3960 socket.socket(),
3961 server_hostname=hostname) as s:
3962 s.connect((HOST, server.port))
3963 # get the data
3964 cb_data = s.get_channel_binding("tls-unique")
3965 if support.verbose:
3966 sys.stdout.write(
3967 " got channel binding data: {0!r}\n".format(cb_data))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003968
Christian Heimes05d9fe32018-02-27 08:55:39 +01003969 # check if it is sane
3970 self.assertIsNotNone(cb_data)
Christian Heimes529525f2018-05-23 22:24:45 +02003971 if s.version() == 'TLSv1.3':
3972 self.assertEqual(len(cb_data), 48)
3973 else:
3974 self.assertEqual(len(cb_data), 12) # True for TLSv1
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003975
Christian Heimes05d9fe32018-02-27 08:55:39 +01003976 # and compare with the peers version
3977 s.write(b"CB tls-unique\n")
3978 peer_data_repr = s.read().strip()
3979 self.assertEqual(peer_data_repr,
3980 repr(cb_data).encode("us-ascii"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003981
3982 # now, again
Christian Heimes05d9fe32018-02-27 08:55:39 +01003983 with client_context.wrap_socket(
3984 socket.socket(),
3985 server_hostname=hostname) as s:
3986 s.connect((HOST, server.port))
3987 new_cb_data = s.get_channel_binding("tls-unique")
3988 if support.verbose:
3989 sys.stdout.write(
3990 "got another channel binding data: {0!r}\n".format(
3991 new_cb_data)
3992 )
3993 # is it really unique
3994 self.assertNotEqual(cb_data, new_cb_data)
3995 self.assertIsNotNone(cb_data)
Christian Heimes529525f2018-05-23 22:24:45 +02003996 if s.version() == 'TLSv1.3':
3997 self.assertEqual(len(cb_data), 48)
3998 else:
3999 self.assertEqual(len(cb_data), 12) # True for TLSv1
Christian Heimes05d9fe32018-02-27 08:55:39 +01004000 s.write(b"CB tls-unique\n")
4001 peer_data_repr = s.read().strip()
4002 self.assertEqual(peer_data_repr,
4003 repr(new_cb_data).encode("us-ascii"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004004
4005 def test_compression(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004006 client_context, server_context, hostname = testing_context()
4007 stats = server_params_test(client_context, server_context,
4008 chatty=True, connectionchatty=True,
4009 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004010 if support.verbose:
4011 sys.stdout.write(" got compression: {!r}\n".format(stats['compression']))
4012 self.assertIn(stats['compression'], { None, 'ZLIB', 'RLE' })
4013
4014 @unittest.skipUnless(hasattr(ssl, 'OP_NO_COMPRESSION'),
4015 "ssl.OP_NO_COMPRESSION needed for this test")
4016 def test_compression_disabled(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004017 client_context, server_context, hostname = testing_context()
4018 client_context.options |= ssl.OP_NO_COMPRESSION
4019 server_context.options |= ssl.OP_NO_COMPRESSION
4020 stats = server_params_test(client_context, server_context,
4021 chatty=True, connectionchatty=True,
4022 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004023 self.assertIs(stats['compression'], None)
4024
Paul Monsonf3550692019-06-19 13:09:54 -07004025 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004026 def test_dh_params(self):
4027 # Check we can get a connection with ephemeral Diffie-Hellman
Christian Heimesa170fa12017-09-15 20:27:30 +02004028 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004029 # test scenario needs TLS <= 1.2
4030 client_context.options |= ssl.OP_NO_TLSv1_3
Christian Heimesa170fa12017-09-15 20:27:30 +02004031 server_context.load_dh_params(DHFILE)
4032 server_context.set_ciphers("kEDH")
Christian Heimes05d9fe32018-02-27 08:55:39 +01004033 server_context.options |= ssl.OP_NO_TLSv1_3
Christian Heimesa170fa12017-09-15 20:27:30 +02004034 stats = server_params_test(client_context, server_context,
4035 chatty=True, connectionchatty=True,
4036 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004037 cipher = stats["cipher"][0]
4038 parts = cipher.split("-")
4039 if "ADH" not in parts and "EDH" not in parts and "DHE" not in parts:
4040 self.fail("Non-DH cipher: " + cipher[0])
4041
Christian Heimesb7b92252018-02-25 09:49:31 +01004042 def test_ecdh_curve(self):
4043 # server secp384r1, client auto
4044 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004045
Christian Heimesb7b92252018-02-25 09:49:31 +01004046 server_context.set_ecdh_curve("secp384r1")
4047 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
Christian Heimesd37b74f2021-04-19 08:31:29 +02004048 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesb7b92252018-02-25 09:49:31 +01004049 stats = server_params_test(client_context, server_context,
4050 chatty=True, connectionchatty=True,
4051 sni_name=hostname)
4052
4053 # server auto, client secp384r1
4054 client_context, server_context, hostname = testing_context()
4055 client_context.set_ecdh_curve("secp384r1")
4056 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
Christian Heimesd37b74f2021-04-19 08:31:29 +02004057 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesb7b92252018-02-25 09:49:31 +01004058 stats = server_params_test(client_context, server_context,
4059 chatty=True, connectionchatty=True,
4060 sni_name=hostname)
4061
4062 # server / client curve mismatch
4063 client_context, server_context, hostname = testing_context()
4064 client_context.set_ecdh_curve("prime256v1")
4065 server_context.set_ecdh_curve("secp384r1")
4066 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
Christian Heimesd37b74f2021-04-19 08:31:29 +02004067 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
4068 with self.assertRaises(ssl.SSLError):
Christian Heimes39258d32021-04-17 11:36:35 +02004069 server_params_test(client_context, server_context,
4070 chatty=True, connectionchatty=True,
4071 sni_name=hostname)
Christian Heimesb7b92252018-02-25 09:49:31 +01004072
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004073 def test_selected_alpn_protocol(self):
4074 # selected_alpn_protocol() is None unless ALPN is used.
Christian Heimesa170fa12017-09-15 20:27:30 +02004075 client_context, server_context, hostname = testing_context()
4076 stats = server_params_test(client_context, server_context,
4077 chatty=True, connectionchatty=True,
4078 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004079 self.assertIs(stats['client_alpn_protocol'], None)
4080
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004081 def test_selected_alpn_protocol_if_server_uses_alpn(self):
4082 # selected_alpn_protocol() is None unless ALPN is used by the client.
Christian Heimesa170fa12017-09-15 20:27:30 +02004083 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004084 server_context.set_alpn_protocols(['foo', 'bar'])
4085 stats = server_params_test(client_context, server_context,
Christian Heimesa170fa12017-09-15 20:27:30 +02004086 chatty=True, connectionchatty=True,
4087 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004088 self.assertIs(stats['client_alpn_protocol'], None)
4089
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004090 def test_alpn_protocols(self):
4091 server_protocols = ['foo', 'bar', 'milkshake']
4092 protocol_tests = [
4093 (['foo', 'bar'], 'foo'),
4094 (['bar', 'foo'], 'foo'),
4095 (['milkshake'], 'milkshake'),
4096 (['http/3.0', 'http/4.0'], None)
4097 ]
4098 for client_protocols, expected in protocol_tests:
Christian Heimesa170fa12017-09-15 20:27:30 +02004099 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004100 server_context.set_alpn_protocols(server_protocols)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004101 client_context.set_alpn_protocols(client_protocols)
4102
4103 try:
4104 stats = server_params_test(client_context,
4105 server_context,
4106 chatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02004107 connectionchatty=True,
4108 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004109 except ssl.SSLError as e:
4110 stats = e
4111
Christian Heimes39258d32021-04-17 11:36:35 +02004112 msg = "failed trying %s (s) and %s (c).\n" \
4113 "was expecting %s, but got %%s from the %%s" \
4114 % (str(server_protocols), str(client_protocols),
4115 str(expected))
4116 client_result = stats['client_alpn_protocol']
4117 self.assertEqual(client_result, expected,
4118 msg % (client_result, "client"))
4119 server_result = stats['server_alpn_protocols'][-1] \
4120 if len(stats['server_alpn_protocols']) else 'nothing'
4121 self.assertEqual(server_result, expected,
4122 msg % (server_result, "server"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004123
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004124 def test_npn_protocols(self):
Christian Heimes39258d32021-04-17 11:36:35 +02004125 assert not ssl.HAS_NPN
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004126
4127 def sni_contexts(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004128 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004129 server_context.load_cert_chain(SIGNED_CERTFILE)
Christian Heimesa170fa12017-09-15 20:27:30 +02004130 other_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004131 other_context.load_cert_chain(SIGNED_CERTFILE2)
Christian Heimesa170fa12017-09-15 20:27:30 +02004132 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004133 client_context.load_verify_locations(SIGNING_CA)
4134 return server_context, other_context, client_context
4135
4136 def check_common_name(self, stats, name):
4137 cert = stats['peercert']
4138 self.assertIn((('commonName', name),), cert['subject'])
4139
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004140 def test_sni_callback(self):
4141 calls = []
4142 server_context, other_context, client_context = self.sni_contexts()
4143
Christian Heimesa170fa12017-09-15 20:27:30 +02004144 client_context.check_hostname = False
4145
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004146 def servername_cb(ssl_sock, server_name, initial_context):
4147 calls.append((server_name, initial_context))
4148 if server_name is not None:
4149 ssl_sock.context = other_context
4150 server_context.set_servername_callback(servername_cb)
4151
4152 stats = server_params_test(client_context, server_context,
4153 chatty=True,
4154 sni_name='supermessage')
4155 # The hostname was fetched properly, and the certificate was
4156 # changed for the connection.
4157 self.assertEqual(calls, [("supermessage", server_context)])
4158 # CERTFILE4 was selected
4159 self.check_common_name(stats, 'fakehostname')
4160
4161 calls = []
4162 # The callback is called with server_name=None
4163 stats = server_params_test(client_context, server_context,
4164 chatty=True,
4165 sni_name=None)
4166 self.assertEqual(calls, [(None, server_context)])
Christian Heimesa170fa12017-09-15 20:27:30 +02004167 self.check_common_name(stats, SIGNED_CERTFILE_HOSTNAME)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004168
4169 # Check disabling the callback
4170 calls = []
4171 server_context.set_servername_callback(None)
4172
4173 stats = server_params_test(client_context, server_context,
4174 chatty=True,
4175 sni_name='notfunny')
4176 # Certificate didn't change
Christian Heimesa170fa12017-09-15 20:27:30 +02004177 self.check_common_name(stats, SIGNED_CERTFILE_HOSTNAME)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004178 self.assertEqual(calls, [])
4179
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004180 def test_sni_callback_alert(self):
4181 # Returning a TLS alert is reflected to the connecting client
4182 server_context, other_context, client_context = self.sni_contexts()
4183
4184 def cb_returning_alert(ssl_sock, server_name, initial_context):
4185 return ssl.ALERT_DESCRIPTION_ACCESS_DENIED
4186 server_context.set_servername_callback(cb_returning_alert)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004187 with self.assertRaises(ssl.SSLError) as cm:
4188 stats = server_params_test(client_context, server_context,
4189 chatty=False,
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004190 sni_name='supermessage')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004191 self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_ACCESS_DENIED')
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004192
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004193 def test_sni_callback_raising(self):
4194 # Raising fails the connection with a TLS handshake failure alert.
4195 server_context, other_context, client_context = self.sni_contexts()
4196
4197 def cb_raising(ssl_sock, server_name, initial_context):
4198 1/0
4199 server_context.set_servername_callback(cb_raising)
4200
Victor Stinner00253502019-06-03 03:51:43 +02004201 with support.catch_unraisable_exception() as catch:
4202 with self.assertRaises(ssl.SSLError) as cm:
4203 stats = server_params_test(client_context, server_context,
4204 chatty=False,
4205 sni_name='supermessage')
4206
4207 self.assertEqual(cm.exception.reason,
4208 'SSLV3_ALERT_HANDSHAKE_FAILURE')
4209 self.assertEqual(catch.unraisable.exc_type, ZeroDivisionError)
Antoine Pitrou50b24d02013-04-11 20:48:42 +02004210
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004211 def test_sni_callback_wrong_return_type(self):
4212 # Returning the wrong return type terminates the TLS connection
4213 # with an internal error alert.
4214 server_context, other_context, client_context = self.sni_contexts()
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004215
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004216 def cb_wrong_return_type(ssl_sock, server_name, initial_context):
4217 return "foo"
4218 server_context.set_servername_callback(cb_wrong_return_type)
4219
Victor Stinner00253502019-06-03 03:51:43 +02004220 with support.catch_unraisable_exception() as catch:
4221 with self.assertRaises(ssl.SSLError) as cm:
4222 stats = server_params_test(client_context, server_context,
4223 chatty=False,
4224 sni_name='supermessage')
4225
4226
4227 self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_INTERNAL_ERROR')
4228 self.assertEqual(catch.unraisable.exc_type, TypeError)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004229
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004230 def test_shared_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004231 client_context, server_context, hostname = testing_context()
Christian Heimese8eb6cb2018-05-22 22:50:12 +02004232 client_context.set_ciphers("AES128:AES256")
4233 server_context.set_ciphers("AES256")
4234 expected_algs = [
4235 "AES256", "AES-256",
4236 # TLS 1.3 ciphers are always enabled
4237 "TLS_CHACHA20", "TLS_AES",
4238 ]
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004239
Christian Heimesa170fa12017-09-15 20:27:30 +02004240 stats = server_params_test(client_context, server_context,
4241 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004242 ciphers = stats['server_shared_ciphers'][0]
4243 self.assertGreater(len(ciphers), 0)
4244 for name, tls_version, bits in ciphers:
Christian Heimese8eb6cb2018-05-22 22:50:12 +02004245 if not any(alg in name for alg in expected_algs):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004246 self.fail(name)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004247
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004248 def test_read_write_after_close_raises_valuerror(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004249 client_context, server_context, hostname = testing_context()
4250 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004251
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004252 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02004253 s = client_context.wrap_socket(socket.socket(),
4254 server_hostname=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004255 s.connect((HOST, server.port))
4256 s.close()
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004257
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004258 self.assertRaises(ValueError, s.read, 1024)
4259 self.assertRaises(ValueError, s.write, b'hello')
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004260
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004261 def test_sendfile(self):
4262 TEST_DATA = b"x" * 512
Hai Shia7f5d932020-08-04 00:41:24 +08004263 with open(os_helper.TESTFN, 'wb') as f:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004264 f.write(TEST_DATA)
Hai Shia7f5d932020-08-04 00:41:24 +08004265 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimes2875c602021-04-19 07:27:10 +02004266 client_context, server_context, hostname = testing_context()
4267 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004268 with server:
Christian Heimes2875c602021-04-19 07:27:10 +02004269 with client_context.wrap_socket(socket.socket(),
4270 server_hostname=hostname) as s:
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004271 s.connect((HOST, server.port))
Hai Shia7f5d932020-08-04 00:41:24 +08004272 with open(os_helper.TESTFN, 'rb') as file:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004273 s.sendfile(file)
4274 self.assertEqual(s.recv(1024), TEST_DATA)
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004275
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004276 def test_session(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004277 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004278 # TODO: sessions aren't compatible with TLSv1.3 yet
4279 client_context.options |= ssl.OP_NO_TLSv1_3
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004280
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004281 # first connection without session
Christian Heimesa170fa12017-09-15 20:27:30 +02004282 stats = server_params_test(client_context, server_context,
4283 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004284 session = stats['session']
4285 self.assertTrue(session.id)
4286 self.assertGreater(session.time, 0)
4287 self.assertGreater(session.timeout, 0)
4288 self.assertTrue(session.has_ticket)
Christian Heimes39258d32021-04-17 11:36:35 +02004289 self.assertGreater(session.ticket_lifetime_hint, 0)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004290 self.assertFalse(stats['session_reused'])
4291 sess_stat = server_context.session_stats()
4292 self.assertEqual(sess_stat['accept'], 1)
4293 self.assertEqual(sess_stat['hits'], 0)
Giampaolo Rodola'915d1412014-06-11 03:54:30 +02004294
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004295 # reuse session
Christian Heimesa170fa12017-09-15 20:27:30 +02004296 stats = server_params_test(client_context, server_context,
4297 session=session, sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004298 sess_stat = server_context.session_stats()
4299 self.assertEqual(sess_stat['accept'], 2)
4300 self.assertEqual(sess_stat['hits'], 1)
4301 self.assertTrue(stats['session_reused'])
4302 session2 = stats['session']
4303 self.assertEqual(session2.id, session.id)
4304 self.assertEqual(session2, session)
4305 self.assertIsNot(session2, session)
4306 self.assertGreaterEqual(session2.time, session.time)
4307 self.assertGreaterEqual(session2.timeout, session.timeout)
Christian Heimes99a65702016-09-10 23:44:53 +02004308
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004309 # another one without session
Christian Heimesa170fa12017-09-15 20:27:30 +02004310 stats = server_params_test(client_context, server_context,
4311 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004312 self.assertFalse(stats['session_reused'])
4313 session3 = stats['session']
4314 self.assertNotEqual(session3.id, session.id)
4315 self.assertNotEqual(session3, session)
4316 sess_stat = server_context.session_stats()
4317 self.assertEqual(sess_stat['accept'], 3)
4318 self.assertEqual(sess_stat['hits'], 1)
Christian Heimes99a65702016-09-10 23:44:53 +02004319
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004320 # reuse session again
Christian Heimesa170fa12017-09-15 20:27:30 +02004321 stats = server_params_test(client_context, server_context,
4322 session=session, sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004323 self.assertTrue(stats['session_reused'])
4324 session4 = stats['session']
4325 self.assertEqual(session4.id, session.id)
4326 self.assertEqual(session4, session)
4327 self.assertGreaterEqual(session4.time, session.time)
4328 self.assertGreaterEqual(session4.timeout, session.timeout)
4329 sess_stat = server_context.session_stats()
4330 self.assertEqual(sess_stat['accept'], 4)
4331 self.assertEqual(sess_stat['hits'], 2)
Christian Heimes99a65702016-09-10 23:44:53 +02004332
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004333 def test_session_handling(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004334 client_context, server_context, hostname = testing_context()
4335 client_context2, _, _ = testing_context()
Christian Heimes99a65702016-09-10 23:44:53 +02004336
Christian Heimes05d9fe32018-02-27 08:55:39 +01004337 # TODO: session reuse does not work with TLSv1.3
Christian Heimesa170fa12017-09-15 20:27:30 +02004338 client_context.options |= ssl.OP_NO_TLSv1_3
4339 client_context2.options |= ssl.OP_NO_TLSv1_3
Christian Heimescb5b68a2017-09-07 18:07:00 -07004340
Christian Heimesa170fa12017-09-15 20:27:30 +02004341 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004342 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02004343 with client_context.wrap_socket(socket.socket(),
4344 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004345 # session is None before handshake
4346 self.assertEqual(s.session, None)
4347 self.assertEqual(s.session_reused, None)
4348 s.connect((HOST, server.port))
4349 session = s.session
4350 self.assertTrue(session)
4351 with self.assertRaises(TypeError) as e:
4352 s.session = object
Ned Deily4531ec72018-06-11 20:26:28 -04004353 self.assertEqual(str(e.exception), 'Value is not a SSLSession.')
Christian Heimes99a65702016-09-10 23:44:53 +02004354
Christian Heimesa170fa12017-09-15 20:27:30 +02004355 with client_context.wrap_socket(socket.socket(),
4356 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004357 s.connect((HOST, server.port))
4358 # cannot set session after handshake
4359 with self.assertRaises(ValueError) as e:
4360 s.session = session
4361 self.assertEqual(str(e.exception),
4362 'Cannot set session after handshake.')
Christian Heimes99a65702016-09-10 23:44:53 +02004363
Christian Heimesa170fa12017-09-15 20:27:30 +02004364 with client_context.wrap_socket(socket.socket(),
4365 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004366 # can set session before handshake and before the
4367 # connection was established
4368 s.session = session
4369 s.connect((HOST, server.port))
4370 self.assertEqual(s.session.id, session.id)
4371 self.assertEqual(s.session, session)
4372 self.assertEqual(s.session_reused, True)
Christian Heimes99a65702016-09-10 23:44:53 +02004373
Christian Heimesa170fa12017-09-15 20:27:30 +02004374 with client_context2.wrap_socket(socket.socket(),
4375 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004376 # cannot re-use session with a different SSLContext
4377 with self.assertRaises(ValueError) as e:
Christian Heimes99a65702016-09-10 23:44:53 +02004378 s.session = session
4379 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004380 self.assertEqual(str(e.exception),
4381 'Session refers to a different SSLContext.')
Christian Heimes99a65702016-09-10 23:44:53 +02004382
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01004383
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02004384@unittest.skipUnless(has_tls_version('TLSv1_3'), "Test needs TLS 1.3")
Christian Heimes9fb051f2018-09-23 08:32:31 +02004385class TestPostHandshakeAuth(unittest.TestCase):
4386 def test_pha_setter(self):
4387 protocols = [
Christian Heimes2875c602021-04-19 07:27:10 +02004388 ssl.PROTOCOL_TLS_SERVER, ssl.PROTOCOL_TLS_CLIENT
Christian Heimes9fb051f2018-09-23 08:32:31 +02004389 ]
4390 for protocol in protocols:
4391 ctx = ssl.SSLContext(protocol)
4392 self.assertEqual(ctx.post_handshake_auth, False)
4393
4394 ctx.post_handshake_auth = True
4395 self.assertEqual(ctx.post_handshake_auth, True)
4396
4397 ctx.verify_mode = ssl.CERT_REQUIRED
4398 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
4399 self.assertEqual(ctx.post_handshake_auth, True)
4400
4401 ctx.post_handshake_auth = False
4402 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
4403 self.assertEqual(ctx.post_handshake_auth, False)
4404
4405 ctx.verify_mode = ssl.CERT_OPTIONAL
4406 ctx.post_handshake_auth = True
4407 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
4408 self.assertEqual(ctx.post_handshake_auth, True)
4409
4410 def test_pha_required(self):
4411 client_context, server_context, hostname = testing_context()
4412 server_context.post_handshake_auth = True
4413 server_context.verify_mode = ssl.CERT_REQUIRED
4414 client_context.post_handshake_auth = True
4415 client_context.load_cert_chain(SIGNED_CERTFILE)
4416
4417 server = ThreadedEchoServer(context=server_context, chatty=False)
4418 with server:
4419 with client_context.wrap_socket(socket.socket(),
4420 server_hostname=hostname) as s:
4421 s.connect((HOST, server.port))
4422 s.write(b'HASCERT')
4423 self.assertEqual(s.recv(1024), b'FALSE\n')
4424 s.write(b'PHA')
4425 self.assertEqual(s.recv(1024), b'OK\n')
4426 s.write(b'HASCERT')
4427 self.assertEqual(s.recv(1024), b'TRUE\n')
4428 # PHA method just returns true when cert is already available
4429 s.write(b'PHA')
4430 self.assertEqual(s.recv(1024), b'OK\n')
4431 s.write(b'GETCERT')
4432 cert_text = s.recv(4096).decode('us-ascii')
4433 self.assertIn('Python Software Foundation CA', cert_text)
4434
4435 def test_pha_required_nocert(self):
4436 client_context, server_context, hostname = testing_context()
4437 server_context.post_handshake_auth = True
4438 server_context.verify_mode = ssl.CERT_REQUIRED
4439 client_context.post_handshake_auth = True
4440
Christian Heimesc8666cf2021-04-24 09:17:54 +02004441 def msg_cb(conn, direction, version, content_type, msg_type, data):
4442 if support.verbose and content_type == _TLSContentType.ALERT:
4443 info = (conn, direction, version, content_type, msg_type, data)
4444 sys.stdout.write(f"TLS: {info!r}\n")
4445
4446 server_context._msg_callback = msg_cb
4447 client_context._msg_callback = msg_cb
4448
4449 server = ThreadedEchoServer(context=server_context, chatty=True)
4450 with server:
4451 with client_context.wrap_socket(socket.socket(),
Miss Islington (bot)d2ab15f2021-06-03 13:15:15 -07004452 server_hostname=hostname,
4453 suppress_ragged_eofs=False) as s:
Christian Heimesc8666cf2021-04-24 09:17:54 +02004454 s.connect((HOST, server.port))
4455 s.write(b'PHA')
Christian Heimesce9a0642021-04-24 15:08:13 +02004456 # test sometimes fails with EOF error. Test passes as long as
4457 # server aborts connection with an error.
Christian Heimesc8666cf2021-04-24 09:17:54 +02004458 with self.assertRaisesRegex(
4459 ssl.SSLError,
Christian Heimesce9a0642021-04-24 15:08:13 +02004460 '(certificate required|EOF occurred)'
Christian Heimesc8666cf2021-04-24 09:17:54 +02004461 ):
Victor Stinner73ea5462019-07-09 14:33:49 +02004462 # receive CertificateRequest
Miss Islington (bot)e5e93e62021-06-02 16:48:40 -07004463 data = s.recv(1024)
Miss Islington (bot)e5e93e62021-06-02 16:48:40 -07004464 self.assertEqual(data, b'OK\n')
4465
Victor Stinner73ea5462019-07-09 14:33:49 +02004466 # send empty Certificate + Finish
4467 s.write(b'HASCERT')
Miss Islington (bot)e5e93e62021-06-02 16:48:40 -07004468
Victor Stinner73ea5462019-07-09 14:33:49 +02004469 # receive alert
Miss Islington (bot)d2ab15f2021-06-03 13:15:15 -07004470 s.recv(1024)
Christian Heimes9fb051f2018-09-23 08:32:31 +02004471
4472 def test_pha_optional(self):
4473 if support.verbose:
4474 sys.stdout.write("\n")
4475
4476 client_context, server_context, hostname = testing_context()
4477 server_context.post_handshake_auth = True
4478 server_context.verify_mode = ssl.CERT_REQUIRED
4479 client_context.post_handshake_auth = True
4480 client_context.load_cert_chain(SIGNED_CERTFILE)
4481
4482 # check CERT_OPTIONAL
4483 server_context.verify_mode = ssl.CERT_OPTIONAL
4484 server = ThreadedEchoServer(context=server_context, chatty=False)
4485 with server:
4486 with client_context.wrap_socket(socket.socket(),
4487 server_hostname=hostname) as s:
4488 s.connect((HOST, server.port))
4489 s.write(b'HASCERT')
4490 self.assertEqual(s.recv(1024), b'FALSE\n')
4491 s.write(b'PHA')
4492 self.assertEqual(s.recv(1024), b'OK\n')
4493 s.write(b'HASCERT')
4494 self.assertEqual(s.recv(1024), b'TRUE\n')
4495
4496 def test_pha_optional_nocert(self):
4497 if support.verbose:
4498 sys.stdout.write("\n")
4499
4500 client_context, server_context, hostname = testing_context()
4501 server_context.post_handshake_auth = True
4502 server_context.verify_mode = ssl.CERT_OPTIONAL
4503 client_context.post_handshake_auth = True
4504
4505 server = ThreadedEchoServer(context=server_context, chatty=False)
4506 with server:
4507 with client_context.wrap_socket(socket.socket(),
4508 server_hostname=hostname) as s:
4509 s.connect((HOST, server.port))
4510 s.write(b'HASCERT')
4511 self.assertEqual(s.recv(1024), b'FALSE\n')
4512 s.write(b'PHA')
4513 self.assertEqual(s.recv(1024), b'OK\n')
penguindustin96466302019-05-06 14:57:17 -04004514 # optional doesn't fail when client does not have a cert
Christian Heimes9fb051f2018-09-23 08:32:31 +02004515 s.write(b'HASCERT')
4516 self.assertEqual(s.recv(1024), b'FALSE\n')
4517
4518 def test_pha_no_pha_client(self):
4519 client_context, server_context, hostname = testing_context()
4520 server_context.post_handshake_auth = True
4521 server_context.verify_mode = ssl.CERT_REQUIRED
4522 client_context.load_cert_chain(SIGNED_CERTFILE)
4523
4524 server = ThreadedEchoServer(context=server_context, chatty=False)
4525 with server:
4526 with client_context.wrap_socket(socket.socket(),
4527 server_hostname=hostname) as s:
4528 s.connect((HOST, server.port))
4529 with self.assertRaisesRegex(ssl.SSLError, 'not server'):
4530 s.verify_client_post_handshake()
4531 s.write(b'PHA')
4532 self.assertIn(b'extension not received', s.recv(1024))
4533
4534 def test_pha_no_pha_server(self):
4535 # server doesn't have PHA enabled, cert is requested in handshake
4536 client_context, server_context, hostname = testing_context()
4537 server_context.verify_mode = ssl.CERT_REQUIRED
4538 client_context.post_handshake_auth = True
4539 client_context.load_cert_chain(SIGNED_CERTFILE)
4540
4541 server = ThreadedEchoServer(context=server_context, chatty=False)
4542 with server:
4543 with client_context.wrap_socket(socket.socket(),
4544 server_hostname=hostname) as s:
4545 s.connect((HOST, server.port))
4546 s.write(b'HASCERT')
4547 self.assertEqual(s.recv(1024), b'TRUE\n')
4548 # PHA doesn't fail if there is already a cert
4549 s.write(b'PHA')
4550 self.assertEqual(s.recv(1024), b'OK\n')
4551 s.write(b'HASCERT')
4552 self.assertEqual(s.recv(1024), b'TRUE\n')
4553
4554 def test_pha_not_tls13(self):
4555 # TLS 1.2
4556 client_context, server_context, hostname = testing_context()
4557 server_context.verify_mode = ssl.CERT_REQUIRED
4558 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
4559 client_context.post_handshake_auth = True
4560 client_context.load_cert_chain(SIGNED_CERTFILE)
4561
4562 server = ThreadedEchoServer(context=server_context, chatty=False)
4563 with server:
4564 with client_context.wrap_socket(socket.socket(),
4565 server_hostname=hostname) as s:
4566 s.connect((HOST, server.port))
4567 # PHA fails for TLS != 1.3
4568 s.write(b'PHA')
4569 self.assertIn(b'WRONG_SSL_VERSION', s.recv(1024))
4570
Christian Heimesf0f59302019-07-01 08:29:17 +02004571 def test_bpo37428_pha_cert_none(self):
4572 # verify that post_handshake_auth does not implicitly enable cert
4573 # validation.
4574 hostname = SIGNED_CERTFILE_HOSTNAME
4575 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4576 client_context.post_handshake_auth = True
4577 client_context.load_cert_chain(SIGNED_CERTFILE)
4578 # no cert validation and CA on client side
4579 client_context.check_hostname = False
4580 client_context.verify_mode = ssl.CERT_NONE
4581
4582 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
4583 server_context.load_cert_chain(SIGNED_CERTFILE)
4584 server_context.load_verify_locations(SIGNING_CA)
4585 server_context.post_handshake_auth = True
4586 server_context.verify_mode = ssl.CERT_REQUIRED
4587
4588 server = ThreadedEchoServer(context=server_context, chatty=False)
4589 with server:
4590 with client_context.wrap_socket(socket.socket(),
4591 server_hostname=hostname) as s:
4592 s.connect((HOST, server.port))
4593 s.write(b'HASCERT')
4594 self.assertEqual(s.recv(1024), b'FALSE\n')
4595 s.write(b'PHA')
4596 self.assertEqual(s.recv(1024), b'OK\n')
4597 s.write(b'HASCERT')
4598 self.assertEqual(s.recv(1024), b'TRUE\n')
4599 # server cert has not been validated
4600 self.assertEqual(s.getpeercert(), {})
4601
Christian Heimes666991f2021-04-26 15:01:40 +02004602 def test_internal_chain_client(self):
4603 client_context, server_context, hostname = testing_context(
4604 server_chain=False
4605 )
4606 server = ThreadedEchoServer(context=server_context, chatty=False)
4607 with server:
4608 with client_context.wrap_socket(
4609 socket.socket(),
4610 server_hostname=hostname
4611 ) as s:
4612 s.connect((HOST, server.port))
4613 vc = s._sslobj.get_verified_chain()
4614 self.assertEqual(len(vc), 2)
4615 ee, ca = vc
4616 uvc = s._sslobj.get_unverified_chain()
4617 self.assertEqual(len(uvc), 1)
4618
4619 self.assertEqual(ee, uvc[0])
4620 self.assertEqual(hash(ee), hash(uvc[0]))
4621 self.assertEqual(repr(ee), repr(uvc[0]))
4622
4623 self.assertNotEqual(ee, ca)
4624 self.assertNotEqual(hash(ee), hash(ca))
4625 self.assertNotEqual(repr(ee), repr(ca))
4626 self.assertNotEqual(ee.get_info(), ca.get_info())
4627 self.assertIn("CN=localhost", repr(ee))
4628 self.assertIn("CN=our-ca-server", repr(ca))
4629
4630 pem = ee.public_bytes(_ssl.ENCODING_PEM)
4631 der = ee.public_bytes(_ssl.ENCODING_DER)
4632 self.assertIsInstance(pem, str)
4633 self.assertIn("-----BEGIN CERTIFICATE-----", pem)
4634 self.assertIsInstance(der, bytes)
4635 self.assertEqual(
4636 ssl.PEM_cert_to_DER_cert(pem), der
4637 )
4638
4639 def test_internal_chain_server(self):
4640 client_context, server_context, hostname = testing_context()
4641 client_context.load_cert_chain(SIGNED_CERTFILE)
4642 server_context.verify_mode = ssl.CERT_REQUIRED
4643 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
4644
4645 server = ThreadedEchoServer(context=server_context, chatty=False)
4646 with server:
4647 with client_context.wrap_socket(
4648 socket.socket(),
4649 server_hostname=hostname
4650 ) as s:
4651 s.connect((HOST, server.port))
4652 s.write(b'VERIFIEDCHAIN\n')
4653 res = s.recv(1024)
4654 self.assertEqual(res, b'\x02\n')
4655 s.write(b'UNVERIFIEDCHAIN\n')
4656 res = s.recv(1024)
4657 self.assertEqual(res, b'\x02\n')
4658
Christian Heimes9fb051f2018-09-23 08:32:31 +02004659
Christian Heimesc7f70692019-05-31 11:44:05 +02004660HAS_KEYLOG = hasattr(ssl.SSLContext, 'keylog_filename')
4661requires_keylog = unittest.skipUnless(
4662 HAS_KEYLOG, 'test requires OpenSSL 1.1.1 with keylog callback')
4663
4664class TestSSLDebug(unittest.TestCase):
4665
Hai Shia7f5d932020-08-04 00:41:24 +08004666 def keylog_lines(self, fname=os_helper.TESTFN):
Christian Heimesc7f70692019-05-31 11:44:05 +02004667 with open(fname) as f:
4668 return len(list(f))
4669
4670 @requires_keylog
Paul Monsonf3550692019-06-19 13:09:54 -07004671 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004672 def test_keylog_defaults(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004673 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004674 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4675 self.assertEqual(ctx.keylog_filename, None)
4676
Hai Shia7f5d932020-08-04 00:41:24 +08004677 self.assertFalse(os.path.isfile(os_helper.TESTFN))
4678 ctx.keylog_filename = os_helper.TESTFN
4679 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
4680 self.assertTrue(os.path.isfile(os_helper.TESTFN))
Christian Heimesc7f70692019-05-31 11:44:05 +02004681 self.assertEqual(self.keylog_lines(), 1)
4682
4683 ctx.keylog_filename = None
4684 self.assertEqual(ctx.keylog_filename, None)
4685
4686 with self.assertRaises((IsADirectoryError, PermissionError)):
4687 # Windows raises PermissionError
4688 ctx.keylog_filename = os.path.dirname(
Hai Shia7f5d932020-08-04 00:41:24 +08004689 os.path.abspath(os_helper.TESTFN))
Christian Heimesc7f70692019-05-31 11:44:05 +02004690
4691 with self.assertRaises(TypeError):
4692 ctx.keylog_filename = 1
4693
4694 @requires_keylog
Paul Monsonf3550692019-06-19 13:09:54 -07004695 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004696 def test_keylog_filename(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004697 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004698 client_context, server_context, hostname = testing_context()
4699
Hai Shia7f5d932020-08-04 00:41:24 +08004700 client_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004701 server = ThreadedEchoServer(context=server_context, chatty=False)
4702 with server:
4703 with client_context.wrap_socket(socket.socket(),
4704 server_hostname=hostname) as s:
4705 s.connect((HOST, server.port))
4706 # header, 5 lines for TLS 1.3
4707 self.assertEqual(self.keylog_lines(), 6)
4708
4709 client_context.keylog_filename = None
Hai Shia7f5d932020-08-04 00:41:24 +08004710 server_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004711 server = ThreadedEchoServer(context=server_context, chatty=False)
4712 with server:
4713 with client_context.wrap_socket(socket.socket(),
4714 server_hostname=hostname) as s:
4715 s.connect((HOST, server.port))
4716 self.assertGreaterEqual(self.keylog_lines(), 11)
4717
Hai Shia7f5d932020-08-04 00:41:24 +08004718 client_context.keylog_filename = os_helper.TESTFN
4719 server_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004720 server = ThreadedEchoServer(context=server_context, chatty=False)
4721 with server:
4722 with client_context.wrap_socket(socket.socket(),
4723 server_hostname=hostname) as s:
4724 s.connect((HOST, server.port))
4725 self.assertGreaterEqual(self.keylog_lines(), 21)
4726
4727 client_context.keylog_filename = None
4728 server_context.keylog_filename = None
4729
4730 @requires_keylog
4731 @unittest.skipIf(sys.flags.ignore_environment,
4732 "test is not compatible with ignore_environment")
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_env(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 with unittest.mock.patch.dict(os.environ):
Hai Shia7f5d932020-08-04 00:41:24 +08004737 os.environ['SSLKEYLOGFILE'] = os_helper.TESTFN
4738 self.assertEqual(os.environ['SSLKEYLOGFILE'], os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004739
4740 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4741 self.assertEqual(ctx.keylog_filename, None)
4742
4743 ctx = ssl.create_default_context()
Hai Shia7f5d932020-08-04 00:41:24 +08004744 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004745
4746 ctx = ssl._create_stdlib_context()
Hai Shia7f5d932020-08-04 00:41:24 +08004747 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004748
4749 def test_msg_callback(self):
4750 client_context, server_context, hostname = testing_context()
4751
4752 def msg_cb(conn, direction, version, content_type, msg_type, data):
4753 pass
4754
4755 self.assertIs(client_context._msg_callback, None)
4756 client_context._msg_callback = msg_cb
4757 self.assertIs(client_context._msg_callback, msg_cb)
4758 with self.assertRaises(TypeError):
4759 client_context._msg_callback = object()
4760
4761 def test_msg_callback_tls12(self):
4762 client_context, server_context, hostname = testing_context()
4763 client_context.options |= ssl.OP_NO_TLSv1_3
4764
4765 msg = []
4766
4767 def msg_cb(conn, direction, version, content_type, msg_type, data):
4768 self.assertIsInstance(conn, ssl.SSLSocket)
4769 self.assertIsInstance(data, bytes)
4770 self.assertIn(direction, {'read', 'write'})
4771 msg.append((direction, version, content_type, msg_type))
4772
4773 client_context._msg_callback = msg_cb
4774
4775 server = ThreadedEchoServer(context=server_context, chatty=False)
4776 with server:
4777 with client_context.wrap_socket(socket.socket(),
4778 server_hostname=hostname) as s:
4779 s.connect((HOST, server.port))
4780
Christian Heimese35d1ba2019-06-03 20:40:15 +02004781 self.assertIn(
Christian Heimesc7f70692019-05-31 11:44:05 +02004782 ("read", TLSVersion.TLSv1_2, _TLSContentType.HANDSHAKE,
4783 _TLSMessageType.SERVER_KEY_EXCHANGE),
Christian Heimese35d1ba2019-06-03 20:40:15 +02004784 msg
4785 )
4786 self.assertIn(
Christian Heimesc7f70692019-05-31 11:44:05 +02004787 ("write", TLSVersion.TLSv1_2, _TLSContentType.CHANGE_CIPHER_SPEC,
4788 _TLSMessageType.CHANGE_CIPHER_SPEC),
Christian Heimese35d1ba2019-06-03 20:40:15 +02004789 msg
4790 )
Christian Heimesc7f70692019-05-31 11:44:05 +02004791
Christian Heimes77cde502021-03-21 16:13:09 +01004792 def test_msg_callback_deadlock_bpo43577(self):
4793 client_context, server_context, hostname = testing_context()
4794 server_context2 = testing_context()[1]
4795
4796 def msg_cb(conn, direction, version, content_type, msg_type, data):
4797 pass
4798
4799 def sni_cb(sock, servername, ctx):
4800 sock.context = server_context2
4801
4802 server_context._msg_callback = msg_cb
4803 server_context.sni_callback = sni_cb
4804
4805 server = ThreadedEchoServer(context=server_context, chatty=False)
4806 with server:
4807 with client_context.wrap_socket(socket.socket(),
4808 server_hostname=hostname) as s:
4809 s.connect((HOST, server.port))
4810 with client_context.wrap_socket(socket.socket(),
4811 server_hostname=hostname) as s:
4812 s.connect((HOST, server.port))
4813
Christian Heimesc7f70692019-05-31 11:44:05 +02004814
Ethan Furmana02cb472021-04-21 10:20:44 -07004815class TestEnumerations(unittest.TestCase):
4816
4817 def test_tlsversion(self):
4818 class CheckedTLSVersion(enum.IntEnum):
4819 MINIMUM_SUPPORTED = _ssl.PROTO_MINIMUM_SUPPORTED
4820 SSLv3 = _ssl.PROTO_SSLv3
4821 TLSv1 = _ssl.PROTO_TLSv1
4822 TLSv1_1 = _ssl.PROTO_TLSv1_1
4823 TLSv1_2 = _ssl.PROTO_TLSv1_2
4824 TLSv1_3 = _ssl.PROTO_TLSv1_3
4825 MAXIMUM_SUPPORTED = _ssl.PROTO_MAXIMUM_SUPPORTED
4826 enum._test_simple_enum(CheckedTLSVersion, TLSVersion)
4827
4828 def test_tlscontenttype(self):
4829 class Checked_TLSContentType(enum.IntEnum):
4830 """Content types (record layer)
4831
4832 See RFC 8446, section B.1
4833 """
4834 CHANGE_CIPHER_SPEC = 20
4835 ALERT = 21
4836 HANDSHAKE = 22
4837 APPLICATION_DATA = 23
4838 # pseudo content types
4839 HEADER = 0x100
4840 INNER_CONTENT_TYPE = 0x101
4841 enum._test_simple_enum(Checked_TLSContentType, _TLSContentType)
4842
4843 def test_tlsalerttype(self):
4844 class Checked_TLSAlertType(enum.IntEnum):
4845 """Alert types for TLSContentType.ALERT messages
4846
4847 See RFC 8466, section B.2
4848 """
4849 CLOSE_NOTIFY = 0
4850 UNEXPECTED_MESSAGE = 10
4851 BAD_RECORD_MAC = 20
4852 DECRYPTION_FAILED = 21
4853 RECORD_OVERFLOW = 22
4854 DECOMPRESSION_FAILURE = 30
4855 HANDSHAKE_FAILURE = 40
4856 NO_CERTIFICATE = 41
4857 BAD_CERTIFICATE = 42
4858 UNSUPPORTED_CERTIFICATE = 43
4859 CERTIFICATE_REVOKED = 44
4860 CERTIFICATE_EXPIRED = 45
4861 CERTIFICATE_UNKNOWN = 46
4862 ILLEGAL_PARAMETER = 47
4863 UNKNOWN_CA = 48
4864 ACCESS_DENIED = 49
4865 DECODE_ERROR = 50
4866 DECRYPT_ERROR = 51
4867 EXPORT_RESTRICTION = 60
4868 PROTOCOL_VERSION = 70
4869 INSUFFICIENT_SECURITY = 71
4870 INTERNAL_ERROR = 80
4871 INAPPROPRIATE_FALLBACK = 86
4872 USER_CANCELED = 90
4873 NO_RENEGOTIATION = 100
4874 MISSING_EXTENSION = 109
4875 UNSUPPORTED_EXTENSION = 110
4876 CERTIFICATE_UNOBTAINABLE = 111
4877 UNRECOGNIZED_NAME = 112
4878 BAD_CERTIFICATE_STATUS_RESPONSE = 113
4879 BAD_CERTIFICATE_HASH_VALUE = 114
4880 UNKNOWN_PSK_IDENTITY = 115
4881 CERTIFICATE_REQUIRED = 116
4882 NO_APPLICATION_PROTOCOL = 120
4883 enum._test_simple_enum(Checked_TLSAlertType, _TLSAlertType)
4884
4885 def test_tlsmessagetype(self):
4886 class Checked_TLSMessageType(enum.IntEnum):
4887 """Message types (handshake protocol)
4888
4889 See RFC 8446, section B.3
4890 """
4891 HELLO_REQUEST = 0
4892 CLIENT_HELLO = 1
4893 SERVER_HELLO = 2
4894 HELLO_VERIFY_REQUEST = 3
4895 NEWSESSION_TICKET = 4
4896 END_OF_EARLY_DATA = 5
4897 HELLO_RETRY_REQUEST = 6
4898 ENCRYPTED_EXTENSIONS = 8
4899 CERTIFICATE = 11
4900 SERVER_KEY_EXCHANGE = 12
4901 CERTIFICATE_REQUEST = 13
4902 SERVER_DONE = 14
4903 CERTIFICATE_VERIFY = 15
4904 CLIENT_KEY_EXCHANGE = 16
4905 FINISHED = 20
4906 CERTIFICATE_URL = 21
4907 CERTIFICATE_STATUS = 22
4908 SUPPLEMENTAL_DATA = 23
4909 KEY_UPDATE = 24
4910 NEXT_PROTO = 67
4911 MESSAGE_HASH = 254
4912 CHANGE_CIPHER_SPEC = 0x0101
4913 enum._test_simple_enum(Checked_TLSMessageType, _TLSMessageType)
4914
4915 def test_sslmethod(self):
4916 Checked_SSLMethod = enum._old_convert_(
4917 enum.IntEnum, '_SSLMethod', 'ssl',
4918 lambda name: name.startswith('PROTOCOL_') and name != 'PROTOCOL_SSLv23',
4919 source=ssl._ssl,
4920 )
4921 enum._test_simple_enum(Checked_SSLMethod, ssl._SSLMethod)
4922
4923 def test_options(self):
4924 CheckedOptions = enum._old_convert_(
4925 enum.FlagEnum, 'Options', 'ssl',
4926 lambda name: name.startswith('OP_'),
4927 source=ssl._ssl,
4928 )
4929 enum._test_simple_enum(CheckedOptions, ssl.Options)
4930
4931
4932 def test_alertdescription(self):
4933 CheckedAlertDescription = enum._old_convert_(
4934 enum.IntEnum, 'AlertDescription', 'ssl',
4935 lambda name: name.startswith('ALERT_DESCRIPTION_'),
4936 source=ssl._ssl,
4937 )
4938 enum._test_simple_enum(CheckedAlertDescription, ssl.AlertDescription)
4939
4940 def test_sslerrornumber(self):
4941 Checked_SSLMethod = enum._old_convert_(
4942 enum.IntEnum, '_SSLMethod', 'ssl',
4943 lambda name: name.startswith('PROTOCOL_') and name != 'PROTOCOL_SSLv23',
4944 source=ssl._ssl,
4945 )
4946 enum._test_simple_enum(Checked_SSLMethod, ssl._SSLMethod)
4947
4948 def test_verifyflags(self):
4949 CheckedVerifyFlags = enum._old_convert_(
4950 enum.FlagEnum, 'VerifyFlags', 'ssl',
4951 lambda name: name.startswith('VERIFY_'),
4952 source=ssl._ssl,
4953 )
4954 enum._test_simple_enum(CheckedVerifyFlags, ssl.VerifyFlags)
4955
4956 def test_verifymode(self):
4957 CheckedVerifyMode = enum._old_convert_(
4958 enum.IntEnum, 'VerifyMode', 'ssl',
4959 lambda name: name.startswith('CERT_'),
4960 source=ssl._ssl,
4961 )
4962 enum._test_simple_enum(CheckedVerifyMode, ssl.VerifyMode)
4963
Thomas Woutersed03b412007-08-28 21:37:11 +00004964def test_main(verbose=False):
Antoine Pitrou15cee622010-08-04 16:45:21 +00004965 if support.verbose:
4966 plats = {
Antoine Pitrou15cee622010-08-04 16:45:21 +00004967 'Mac': platform.mac_ver,
4968 'Windows': platform.win32_ver,
4969 }
Petr Viktorin8b94b412018-05-16 11:51:18 -04004970 for name, func in plats.items():
4971 plat = func()
4972 if plat and plat[0]:
4973 plat = '%s %r' % (name, plat)
4974 break
4975 else:
4976 plat = repr(platform.platform())
Antoine Pitrou15cee622010-08-04 16:45:21 +00004977 print("test_ssl: testing with %r %r" %
4978 (ssl.OPENSSL_VERSION, ssl.OPENSSL_VERSION_INFO))
4979 print(" under %s" % plat)
Antoine Pitroud5323212010-10-22 18:19:07 +00004980 print(" HAS_SNI = %r" % ssl.HAS_SNI)
Antoine Pitrou609ef012013-03-29 18:09:06 +01004981 print(" OP_ALL = 0x%8x" % ssl.OP_ALL)
4982 try:
4983 print(" OP_NO_TLSv1_1 = 0x%8x" % ssl.OP_NO_TLSv1_1)
4984 except AttributeError:
4985 pass
Antoine Pitrou15cee622010-08-04 16:45:21 +00004986
Antoine Pitrou152efa22010-05-16 18:19:27 +00004987 for filename in [
Martin Panter3840b2a2016-03-27 01:53:46 +00004988 CERTFILE, BYTES_CERTFILE,
Antoine Pitrou152efa22010-05-16 18:19:27 +00004989 ONLYCERT, ONLYKEY, BYTES_ONLYCERT, BYTES_ONLYKEY,
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004990 SIGNED_CERTFILE, SIGNED_CERTFILE2, SIGNING_CA,
Antoine Pitrou152efa22010-05-16 18:19:27 +00004991 BADCERT, BADKEY, EMPTYCERT]:
4992 if not os.path.exists(filename):
4993 raise support.TestFailed("Can't read certificate file %r" % filename)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004994
Martin Panter3840b2a2016-03-27 01:53:46 +00004995 tests = [
4996 ContextTests, BasicSocketTests, SSLErrorTests, MemoryBIOTests,
Christian Heimes9d50ab52018-02-27 10:17:30 +01004997 SSLObjectTests, SimpleBackgroundTests, ThreadedTests,
Christian Heimesc7f70692019-05-31 11:44:05 +02004998 TestPostHandshakeAuth, TestSSLDebug
Martin Panter3840b2a2016-03-27 01:53:46 +00004999 ]
Thomas Woutersed03b412007-08-28 21:37:11 +00005000
Benjamin Petersonee8712c2008-05-20 21:35:26 +00005001 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00005002 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00005003
Hai Shie80697d2020-05-28 06:10:27 +08005004 thread_info = threading_helper.threading_setup()
Antoine Pitrou480a1242010-04-28 21:37:09 +00005005 try:
5006 support.run_unittest(*tests)
5007 finally:
Hai Shie80697d2020-05-28 06:10:27 +08005008 threading_helper.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00005009
5010if __name__ == "__main__":
5011 test_main()