blob: 31e1e7311daa560c7de895d55a61ecd6ed08a6bb [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")
Antoine Pitrou05d936d2010-10-13 11:38:36 +000035
Ethan Furmana02cb472021-04-21 10:20:44 -070036from ssl import TLSVersion, _TLSContentType, _TLSMessageType, _TLSAlertType
Martin Panter3840b2a2016-03-27 01:53:46 +000037
Paul Monsonf3550692019-06-19 13:09:54 -070038Py_DEBUG = hasattr(sys, 'gettotalrefcount')
39Py_DEBUG_WIN32 = Py_DEBUG and sys.platform == 'win32'
40
Antoine Pitrou2463e5f2013-03-28 22:24:43 +010041PROTOCOLS = sorted(ssl._PROTOCOL_NAMES)
Serhiy Storchaka16994912020-04-25 10:06:29 +030042HOST = socket_helper.HOST
Christian Heimesd37b74f2021-04-19 08:31:29 +020043IS_OPENSSL_3_0_0 = ssl.OPENSSL_VERSION_INFO >= (3, 0, 0)
Christian Heimes892d66e2018-01-29 14:10:18 +010044PY_SSL_DEFAULT_CIPHERS = sysconfig.get_config_var('PY_SSL_DEFAULT_CIPHERS')
Antoine Pitrou152efa22010-05-16 18:19:27 +000045
Victor Stinner3ef63442019-02-19 18:06:03 +010046PROTOCOL_TO_TLS_VERSION = {}
47for proto, ver in (
48 ("PROTOCOL_SSLv23", "SSLv3"),
49 ("PROTOCOL_TLSv1", "TLSv1"),
50 ("PROTOCOL_TLSv1_1", "TLSv1_1"),
51):
52 try:
53 proto = getattr(ssl, proto)
54 ver = getattr(ssl.TLSVersion, ver)
55 except AttributeError:
56 continue
57 PROTOCOL_TO_TLS_VERSION[proto] = ver
58
Christian Heimesefff7062013-11-21 03:35:02 +010059def data_file(*name):
60 return os.path.join(os.path.dirname(__file__), *name)
Antoine Pitrou152efa22010-05-16 18:19:27 +000061
Antoine Pitrou81564092010-10-08 23:06:24 +000062# The custom key and certificate files used in test_ssl are generated
63# using Lib/test/make_ssl_certs.py.
64# Other certificates are simply fetched from the Internet servers they
65# are meant to authenticate.
66
Antoine Pitrou152efa22010-05-16 18:19:27 +000067CERTFILE = data_file("keycert.pem")
Victor Stinner313a1202010-06-11 23:56:51 +000068BYTES_CERTFILE = os.fsencode(CERTFILE)
Antoine Pitrou152efa22010-05-16 18:19:27 +000069ONLYCERT = data_file("ssl_cert.pem")
70ONLYKEY = data_file("ssl_key.pem")
Victor Stinner313a1202010-06-11 23:56:51 +000071BYTES_ONLYCERT = os.fsencode(ONLYCERT)
72BYTES_ONLYKEY = os.fsencode(ONLYKEY)
Antoine Pitrou4fd1e6a2011-08-25 14:39:44 +020073CERTFILE_PROTECTED = data_file("keycert.passwd.pem")
74ONLYKEY_PROTECTED = data_file("ssl_key.passwd.pem")
75KEY_PASSWORD = "somepass"
Antoine Pitrou152efa22010-05-16 18:19:27 +000076CAPATH = data_file("capath")
Victor Stinner313a1202010-06-11 23:56:51 +000077BYTES_CAPATH = os.fsencode(CAPATH)
Christian Heimesefff7062013-11-21 03:35:02 +010078CAFILE_NEURONIO = data_file("capath", "4e1295a3.0")
79CAFILE_CACERT = data_file("capath", "5ed36f99.0")
80
Christian Heimesbd5c7d22018-01-20 15:16:30 +010081CERTFILE_INFO = {
82 'issuer': ((('countryName', 'XY'),),
83 (('localityName', 'Castle Anthrax'),),
84 (('organizationName', 'Python Software Foundation'),),
85 (('commonName', 'localhost'),)),
Christian Heimese6dac002018-08-30 07:25:49 +020086 'notAfter': 'Aug 26 14:23:15 2028 GMT',
87 'notBefore': 'Aug 29 14:23:15 2018 GMT',
88 'serialNumber': '98A7CF88C74A32ED',
Christian Heimesbd5c7d22018-01-20 15:16:30 +010089 'subject': ((('countryName', 'XY'),),
90 (('localityName', 'Castle Anthrax'),),
91 (('organizationName', 'Python Software Foundation'),),
92 (('commonName', 'localhost'),)),
93 'subjectAltName': (('DNS', 'localhost'),),
94 'version': 3
95}
Antoine Pitrou152efa22010-05-16 18:19:27 +000096
Christian Heimes22587792013-11-21 23:56:13 +010097# empty CRL
98CRLFILE = data_file("revocation.crl")
99
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100100# Two keys and certs signed by the same CA (for SNI tests)
101SIGNED_CERTFILE = data_file("keycert3.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +0200102SIGNED_CERTFILE_HOSTNAME = 'localhost'
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100103
104SIGNED_CERTFILE_INFO = {
105 'OCSP': ('http://testca.pythontest.net/testca/ocsp/',),
106 'caIssuers': ('http://testca.pythontest.net/testca/pycacert.cer',),
107 'crlDistributionPoints': ('http://testca.pythontest.net/testca/revocation.crl',),
108 'issuer': ((('countryName', 'XY'),),
109 (('organizationName', 'Python Software Foundation CA'),),
110 (('commonName', 'our-ca-server'),)),
Christian Heimesb467d9a2021-04-17 10:07:19 +0200111 'notAfter': 'Oct 28 14:23:16 2037 GMT',
Christian Heimese6dac002018-08-30 07:25:49 +0200112 'notBefore': 'Aug 29 14:23:16 2018 GMT',
113 'serialNumber': 'CB2D80995A69525C',
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100114 'subject': ((('countryName', 'XY'),),
115 (('localityName', 'Castle Anthrax'),),
116 (('organizationName', 'Python Software Foundation'),),
117 (('commonName', 'localhost'),)),
118 'subjectAltName': (('DNS', 'localhost'),),
119 'version': 3
120}
121
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100122SIGNED_CERTFILE2 = data_file("keycert4.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +0200123SIGNED_CERTFILE2_HOSTNAME = 'fakehostname'
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100124SIGNED_CERTFILE_ECC = data_file("keycertecc.pem")
125SIGNED_CERTFILE_ECC_HOSTNAME = 'localhost-ecc'
126
Martin Panter3840b2a2016-03-27 01:53:46 +0000127# Same certificate as pycacert.pem, but without extra text in file
128SIGNING_CA = data_file("capath", "ceff1710.0")
Christian Heimes1c03abd2016-09-06 23:25:35 +0200129# cert with all kinds of subject alt names
130ALLSANFILE = data_file("allsans.pem")
Christian Heimes66e57422018-01-29 14:25:13 +0100131IDNSANSFILE = data_file("idnsans.pem")
Christian Heimesb467d9a2021-04-17 10:07:19 +0200132NOSANFILE = data_file("nosan.pem")
133NOSAN_HOSTNAME = 'localhost'
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100134
Martin Panter3d81d932016-01-14 09:36:00 +0000135REMOTE_HOST = "self-signed.pythontest.net"
Antoine Pitrou152efa22010-05-16 18:19:27 +0000136
137EMPTYCERT = data_file("nullcert.pem")
138BADCERT = data_file("badcert.pem")
Martin Panter407b62f2016-01-30 03:41:43 +0000139NONEXISTINGCERT = data_file("XXXnonexisting.pem")
Antoine Pitrou152efa22010-05-16 18:19:27 +0000140BADKEY = data_file("badkey.pem")
Antoine Pitroud8c347a2011-10-01 19:20:25 +0200141NOKIACERT = data_file("nokia.pem")
Christian Heimes824f7f32013-08-17 00:54:47 +0200142NULLBYTECERT = data_file("nullbytecert.pem")
Christian Heimesa37f5242019-01-15 23:47:42 +0100143TALOS_INVALID_CRLDP = data_file("talos-2019-0758.pem")
Antoine Pitrou152efa22010-05-16 18:19:27 +0000144
Christian Heimes88bfd0b2018-08-14 12:54:19 +0200145DHFILE = data_file("ffdh3072.pem")
Antoine Pitrou0e576f12011-12-22 10:03:38 +0100146BYTES_DHFILE = os.fsencode(DHFILE)
Thomas Woutersed03b412007-08-28 21:37:11 +0000147
Christian Heimes358cfd42016-09-10 22:43:48 +0200148# Not defined in all versions of OpenSSL
149OP_NO_COMPRESSION = getattr(ssl, "OP_NO_COMPRESSION", 0)
150OP_SINGLE_DH_USE = getattr(ssl, "OP_SINGLE_DH_USE", 0)
151OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0)
152OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0)
Christian Heimes05d9fe32018-02-27 08:55:39 +0100153OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0)
Christian Heimes6f37ebc2021-04-09 17:59:21 +0200154OP_IGNORE_UNEXPECTED_EOF = getattr(ssl, "OP_IGNORE_UNEXPECTED_EOF", 0)
Christian Heimes358cfd42016-09-10 22:43:48 +0200155
Christian Heimesf6c6b582021-03-18 23:06:50 +0100156# Ubuntu has patched OpenSSL and changed behavior of security level 2
157# see https://bugs.python.org/issue41561#msg389003
158def is_ubuntu():
159 try:
160 # Assume that any references of "ubuntu" implies Ubuntu-like distro
161 # The workaround is not required for 18.04, but doesn't hurt either.
162 with open("/etc/os-release", encoding="utf-8") as f:
163 return "ubuntu" in f.read()
164 except FileNotFoundError:
165 return False
166
167if is_ubuntu():
168 def seclevel_workaround(*ctxs):
169 """"Lower security level to '1' and allow all ciphers for TLS 1.0/1"""
170 for ctx in ctxs:
Christian Heimes34477502021-04-12 12:00:38 +0200171 if (
172 hasattr(ctx, "minimum_version") and
173 ctx.minimum_version <= ssl.TLSVersion.TLSv1_1
174 ):
Christian Heimesf6c6b582021-03-18 23:06:50 +0100175 ctx.set_ciphers("@SECLEVEL=1:ALL")
176else:
177 def seclevel_workaround(*ctxs):
178 pass
179
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100180
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200181def has_tls_protocol(protocol):
182 """Check if a TLS protocol is available and enabled
183
184 :param protocol: enum ssl._SSLMethod member or name
185 :return: bool
186 """
187 if isinstance(protocol, str):
188 assert protocol.startswith('PROTOCOL_')
189 protocol = getattr(ssl, protocol, None)
190 if protocol is None:
191 return False
192 if protocol in {
193 ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS_SERVER,
194 ssl.PROTOCOL_TLS_CLIENT
195 }:
196 # auto-negotiate protocols are always available
197 return True
198 name = protocol.name
199 return has_tls_version(name[len('PROTOCOL_'):])
200
201
202@functools.lru_cache
203def has_tls_version(version):
204 """Check if a TLS/SSL version is enabled
205
206 :param version: TLS version name or ssl.TLSVersion member
207 :return: bool
208 """
209 if version == "SSLv2":
210 # never supported and not even in TLSVersion enum
211 return False
212
213 if isinstance(version, str):
214 version = ssl.TLSVersion.__members__[version]
215
216 # check compile time flags like ssl.HAS_TLSv1_2
217 if not getattr(ssl, f'HAS_{version.name}'):
218 return False
219
Christian Heimes5151d642021-04-09 15:43:06 +0200220 if IS_OPENSSL_3_0_0 and version < ssl.TLSVersion.TLSv1_2:
221 # bpo43791: 3.0.0-alpha14 fails with TLSV1_ALERT_INTERNAL_ERROR
222 return False
223
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200224 # check runtime and dynamic crypto policy settings. A TLS version may
225 # be compiled in but disabled by a policy or config option.
Christian Heimes2875c602021-04-19 07:27:10 +0200226 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200227 if (
Christian Heimes9f772682019-09-26 18:23:17 +0200228 hasattr(ctx, 'minimum_version') and
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200229 ctx.minimum_version != ssl.TLSVersion.MINIMUM_SUPPORTED and
230 version < ctx.minimum_version
231 ):
232 return False
233 if (
Christian Heimes9f772682019-09-26 18:23:17 +0200234 hasattr(ctx, 'maximum_version') and
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200235 ctx.maximum_version != ssl.TLSVersion.MAXIMUM_SUPPORTED and
236 version > ctx.maximum_version
237 ):
238 return False
239
240 return True
241
242
243def requires_tls_version(version):
244 """Decorator to skip tests when a required TLS version is not available
245
246 :param version: TLS version name or ssl.TLSVersion member
247 :return:
248 """
249 def decorator(func):
250 @functools.wraps(func)
251 def wrapper(*args, **kw):
252 if not has_tls_version(version):
253 raise unittest.SkipTest(f"{version} is not available.")
254 else:
255 return func(*args, **kw)
256 return wrapper
257 return decorator
258
259
Thomas Woutersed03b412007-08-28 21:37:11 +0000260def handle_error(prefix):
261 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000262 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000263 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +0000264
Christian Heimesb7b92252018-02-25 09:49:31 +0100265
Antoine Pitrouc695c952014-04-28 20:57:36 +0200266def utc_offset(): #NOTE: ignore issues like #1647654
267 # local time = utc time + utc offset
268 if time.daylight and time.localtime().tm_isdst > 0:
269 return -time.altzone # seconds
270 return -time.timezone
271
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100272
Christian Heimes2875c602021-04-19 07:27:10 +0200273ignore_deprecation = warnings_helper.ignore_warnings(
274 category=DeprecationWarning
275)
Antoine Pitrou23df4832010-08-04 17:14:06 +0000276
Christian Heimes2875c602021-04-19 07:27:10 +0200277
278def test_wrap_socket(sock, *,
Christian Heimesd0486372016-09-10 23:23:33 +0200279 cert_reqs=ssl.CERT_NONE, ca_certs=None,
280 ciphers=None, certfile=None, keyfile=None,
281 **kwargs):
Christian Heimes2875c602021-04-19 07:27:10 +0200282 if not kwargs.get("server_side"):
283 kwargs["server_hostname"] = SIGNED_CERTFILE_HOSTNAME
284 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
285 else:
286 context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimesd0486372016-09-10 23:23:33 +0200287 if cert_reqs is not None:
Christian Heimesa170fa12017-09-15 20:27:30 +0200288 if cert_reqs == ssl.CERT_NONE:
289 context.check_hostname = False
Christian Heimesd0486372016-09-10 23:23:33 +0200290 context.verify_mode = cert_reqs
291 if ca_certs is not None:
292 context.load_verify_locations(ca_certs)
293 if certfile is not None or keyfile is not None:
294 context.load_cert_chain(certfile, keyfile)
295 if ciphers is not None:
296 context.set_ciphers(ciphers)
297 return context.wrap_socket(sock, **kwargs)
298
Christian Heimesa170fa12017-09-15 20:27:30 +0200299
300def testing_context(server_cert=SIGNED_CERTFILE):
301 """Create context
302
303 client_context, server_context, hostname = testing_context()
304 """
305 if server_cert == SIGNED_CERTFILE:
306 hostname = SIGNED_CERTFILE_HOSTNAME
307 elif server_cert == SIGNED_CERTFILE2:
308 hostname = SIGNED_CERTFILE2_HOSTNAME
Christian Heimesb467d9a2021-04-17 10:07:19 +0200309 elif server_cert == NOSANFILE:
310 hostname = NOSAN_HOSTNAME
Christian Heimesa170fa12017-09-15 20:27:30 +0200311 else:
312 raise ValueError(server_cert)
313
314 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
315 client_context.load_verify_locations(SIGNING_CA)
316
317 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
318 server_context.load_cert_chain(server_cert)
Christian Heimes9fb051f2018-09-23 08:32:31 +0200319 server_context.load_verify_locations(SIGNING_CA)
Christian Heimesa170fa12017-09-15 20:27:30 +0200320
321 return client_context, server_context, hostname
322
323
Antoine Pitrou152efa22010-05-16 18:19:27 +0000324class BasicSocketTests(unittest.TestCase):
Thomas Woutersed03b412007-08-28 21:37:11 +0000325
Antoine Pitrou480a1242010-04-28 21:37:09 +0000326 def test_constants(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000327 ssl.CERT_NONE
328 ssl.CERT_OPTIONAL
329 ssl.CERT_REQUIRED
Antoine Pitrou6db49442011-12-19 13:27:11 +0100330 ssl.OP_CIPHER_SERVER_PREFERENCE
Antoine Pitrou0e576f12011-12-22 10:03:38 +0100331 ssl.OP_SINGLE_DH_USE
Christian Heimesd37b74f2021-04-19 08:31:29 +0200332 ssl.OP_SINGLE_ECDH_USE
Christian Heimes39258d32021-04-17 11:36:35 +0200333 ssl.OP_NO_COMPRESSION
Christian Heimesd37b74f2021-04-19 08:31:29 +0200334 self.assertEqual(ssl.HAS_SNI, True)
335 self.assertEqual(ssl.HAS_ECDH, True)
336 self.assertEqual(ssl.HAS_TLSv1_2, True)
337 self.assertEqual(ssl.HAS_TLSv1_3, True)
Christian Heimescb5b68a2017-09-07 18:07:00 -0700338 ssl.OP_NO_SSLv2
339 ssl.OP_NO_SSLv3
340 ssl.OP_NO_TLSv1
341 ssl.OP_NO_TLSv1_3
Christian Heimes39258d32021-04-17 11:36:35 +0200342 ssl.OP_NO_TLSv1_1
343 ssl.OP_NO_TLSv1_2
Christian Heimesa170fa12017-09-15 20:27:30 +0200344 self.assertEqual(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv23)
Thomas Woutersed03b412007-08-28 21:37:11 +0000345
Christian Heimes9d50ab52018-02-27 10:17:30 +0100346 def test_private_init(self):
347 with self.assertRaisesRegex(TypeError, "public constructor"):
348 with socket.socket() as s:
349 ssl.SSLSocket(s)
350
Antoine Pitrou172f0252014-04-18 20:33:08 +0200351 def test_str_for_enums(self):
352 # Make sure that the PROTOCOL_* constants have enum-like string
353 # reprs.
Christian Heimes2875c602021-04-19 07:27:10 +0200354 proto = ssl.PROTOCOL_TLS_CLIENT
355 self.assertEqual(str(proto), 'PROTOCOL_TLS_CLIENT')
Antoine Pitrou172f0252014-04-18 20:33:08 +0200356 ctx = ssl.SSLContext(proto)
357 self.assertIs(ctx.protocol, proto)
358
Antoine Pitrou480a1242010-04-28 21:37:09 +0000359 def test_random(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000360 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000361 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000362 sys.stdout.write("\n RAND_status is %d (%s)\n"
363 % (v, (v and "sufficient randomness") or
364 "insufficient randomness"))
Victor Stinner99c8b162011-05-24 12:05:19 +0200365
Christian Heimes2875c602021-04-19 07:27:10 +0200366 with warnings_helper.check_warnings():
367 data, is_cryptographic = ssl.RAND_pseudo_bytes(16)
Victor Stinner99c8b162011-05-24 12:05:19 +0200368 self.assertEqual(len(data), 16)
369 self.assertEqual(is_cryptographic, v == 1)
370 if v:
371 data = ssl.RAND_bytes(16)
372 self.assertEqual(len(data), 16)
Victor Stinner2e2baa92011-05-25 11:15:16 +0200373 else:
374 self.assertRaises(ssl.SSLError, ssl.RAND_bytes, 16)
Victor Stinner99c8b162011-05-24 12:05:19 +0200375
Victor Stinner1e81a392013-12-19 16:47:04 +0100376 # negative num is invalid
377 self.assertRaises(ValueError, ssl.RAND_bytes, -5)
Christian Heimes2875c602021-04-19 07:27:10 +0200378 with warnings_helper.check_warnings():
379 self.assertRaises(ValueError, ssl.RAND_pseudo_bytes, -5)
Victor Stinner1e81a392013-12-19 16:47:04 +0100380
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000381 ssl.RAND_add("this is a random string", 75.0)
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200382 ssl.RAND_add(b"this is a random bytes object", 75.0)
383 ssl.RAND_add(bytearray(b"this is a random bytearray object"), 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +0000384
Antoine Pitrou480a1242010-04-28 21:37:09 +0000385 def test_parse_cert(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000386 # note that this uses an 'unofficial' function in _ssl.c,
387 # provided solely for this test, to exercise the certificate
388 # parsing code
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100389 self.assertEqual(
390 ssl._ssl._test_decode_cert(CERTFILE),
391 CERTFILE_INFO
392 )
393 self.assertEqual(
394 ssl._ssl._test_decode_cert(SIGNED_CERTFILE),
395 SIGNED_CERTFILE_INFO
396 )
397
Antoine Pitroud8c347a2011-10-01 19:20:25 +0200398 # Issue #13034: the subjectAltName in some certificates
399 # (notably projects.developer.nokia.com:443) wasn't parsed
400 p = ssl._ssl._test_decode_cert(NOKIACERT)
401 if support.verbose:
402 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
403 self.assertEqual(p['subjectAltName'],
404 (('DNS', 'projects.developer.nokia.com'),
405 ('DNS', 'projects.forum.nokia.com'))
406 )
Christian Heimesbd3a7f92013-11-21 03:40:15 +0100407 # extra OCSP and AIA fields
408 self.assertEqual(p['OCSP'], ('http://ocsp.verisign.com',))
409 self.assertEqual(p['caIssuers'],
410 ('http://SVRIntl-G3-aia.verisign.com/SVRIntlG3.cer',))
411 self.assertEqual(p['crlDistributionPoints'],
412 ('http://SVRIntl-G3-crl.verisign.com/SVRIntlG3.crl',))
Thomas Woutersed03b412007-08-28 21:37:11 +0000413
Christian Heimesa37f5242019-01-15 23:47:42 +0100414 def test_parse_cert_CVE_2019_5010(self):
415 p = ssl._ssl._test_decode_cert(TALOS_INVALID_CRLDP)
416 if support.verbose:
417 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
418 self.assertEqual(
419 p,
420 {
421 'issuer': (
422 (('countryName', 'UK'),), (('commonName', 'cody-ca'),)),
423 'notAfter': 'Jun 14 18:00:58 2028 GMT',
424 'notBefore': 'Jun 18 18:00:58 2018 GMT',
425 'serialNumber': '02',
426 'subject': ((('countryName', 'UK'),),
427 (('commonName',
428 'codenomicon-vm-2.test.lal.cisco.com'),)),
429 'subjectAltName': (
430 ('DNS', 'codenomicon-vm-2.test.lal.cisco.com'),),
431 'version': 3
432 }
433 )
434
Christian Heimes824f7f32013-08-17 00:54:47 +0200435 def test_parse_cert_CVE_2013_4238(self):
436 p = ssl._ssl._test_decode_cert(NULLBYTECERT)
437 if support.verbose:
438 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
439 subject = ((('countryName', 'US'),),
440 (('stateOrProvinceName', 'Oregon'),),
441 (('localityName', 'Beaverton'),),
442 (('organizationName', 'Python Software Foundation'),),
443 (('organizationalUnitName', 'Python Core Development'),),
444 (('commonName', 'null.python.org\x00example.org'),),
445 (('emailAddress', 'python-dev@python.org'),))
446 self.assertEqual(p['subject'], subject)
447 self.assertEqual(p['issuer'], subject)
Christian Heimes157c9832013-08-25 14:12:41 +0200448 if ssl._OPENSSL_API_VERSION >= (0, 9, 8):
449 san = (('DNS', 'altnull.python.org\x00example.com'),
450 ('email', 'null@python.org\x00user@example.org'),
451 ('URI', 'http://null.python.org\x00http://example.org'),
452 ('IP Address', '192.0.2.1'),
Christian Heimes2b7de662019-12-07 17:59:36 +0100453 ('IP Address', '2001:DB8:0:0:0:0:0:1'))
Christian Heimes157c9832013-08-25 14:12:41 +0200454 else:
455 # OpenSSL 0.9.7 doesn't support IPv6 addresses in subjectAltName
456 san = (('DNS', 'altnull.python.org\x00example.com'),
457 ('email', 'null@python.org\x00user@example.org'),
458 ('URI', 'http://null.python.org\x00http://example.org'),
459 ('IP Address', '192.0.2.1'),
460 ('IP Address', '<invalid>'))
461
462 self.assertEqual(p['subjectAltName'], san)
Christian Heimes824f7f32013-08-17 00:54:47 +0200463
Christian Heimes1c03abd2016-09-06 23:25:35 +0200464 def test_parse_all_sans(self):
465 p = ssl._ssl._test_decode_cert(ALLSANFILE)
466 self.assertEqual(p['subjectAltName'],
467 (
468 ('DNS', 'allsans'),
469 ('othername', '<unsupported>'),
470 ('othername', '<unsupported>'),
471 ('email', 'user@example.org'),
472 ('DNS', 'www.example.org'),
473 ('DirName',
474 ((('countryName', 'XY'),),
475 (('localityName', 'Castle Anthrax'),),
476 (('organizationName', 'Python Software Foundation'),),
477 (('commonName', 'dirname example'),))),
478 ('URI', 'https://www.python.org/'),
479 ('IP Address', '127.0.0.1'),
Christian Heimes2b7de662019-12-07 17:59:36 +0100480 ('IP Address', '0:0:0:0:0:0:0:1'),
Christian Heimes1c03abd2016-09-06 23:25:35 +0200481 ('Registered ID', '1.2.3.4.5')
482 )
483 )
484
Antoine Pitrou480a1242010-04-28 21:37:09 +0000485 def test_DER_to_PEM(self):
Martin Panter3d81d932016-01-14 09:36:00 +0000486 with open(CAFILE_CACERT, 'r') as f:
Antoine Pitrou480a1242010-04-28 21:37:09 +0000487 pem = f.read()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000488 d1 = ssl.PEM_cert_to_DER_cert(pem)
489 p2 = ssl.DER_cert_to_PEM_cert(d1)
490 d2 = ssl.PEM_cert_to_DER_cert(p2)
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000491 self.assertEqual(d1, d2)
Antoine Pitrou9bfbe612010-04-27 22:08:08 +0000492 if not p2.startswith(ssl.PEM_HEADER + '\n'):
493 self.fail("DER-to-PEM didn't include correct header:\n%r\n" % p2)
494 if not p2.endswith('\n' + ssl.PEM_FOOTER + '\n'):
495 self.fail("DER-to-PEM didn't include correct footer:\n%r\n" % p2)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000496
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000497 def test_openssl_version(self):
498 n = ssl.OPENSSL_VERSION_NUMBER
499 t = ssl.OPENSSL_VERSION_INFO
500 s = ssl.OPENSSL_VERSION
501 self.assertIsInstance(n, int)
502 self.assertIsInstance(t, tuple)
503 self.assertIsInstance(s, str)
504 # Some sanity checks follow
Christian Heimesd37b74f2021-04-19 08:31:29 +0200505 # >= 1.1.1
506 self.assertGreaterEqual(n, 0x10101000)
Christian Heimes2b7de662019-12-07 17:59:36 +0100507 # < 4.0
508 self.assertLess(n, 0x40000000)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000509 major, minor, fix, patch, status = t
Christian Heimes2b7de662019-12-07 17:59:36 +0100510 self.assertGreaterEqual(major, 1)
511 self.assertLess(major, 4)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000512 self.assertGreaterEqual(minor, 0)
513 self.assertLess(minor, 256)
514 self.assertGreaterEqual(fix, 0)
515 self.assertLess(fix, 256)
516 self.assertGreaterEqual(patch, 0)
Ned Deily05784a72015-02-05 17:20:13 +1100517 self.assertLessEqual(patch, 63)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000518 self.assertGreaterEqual(status, 0)
519 self.assertLessEqual(status, 15)
Christian Heimesd37b74f2021-04-19 08:31:29 +0200520
521 libressl_ver = f"LibreSSL {major:d}"
522 openssl_ver = f"OpenSSL {major:d}.{minor:d}.{fix:d}"
523 self.assertTrue(
524 s.startswith((openssl_ver, libressl_ver)),
525 (s, t, hex(n))
526 )
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000527
Antoine Pitrou9d543662010-04-23 23:10:32 +0000528 @support.cpython_only
529 def test_refcycle(self):
530 # Issue #7943: an SSL object doesn't create reference cycles with
531 # itself.
532 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200533 ss = test_wrap_socket(s)
Antoine Pitrou9d543662010-04-23 23:10:32 +0000534 wr = weakref.ref(ss)
Hai Shia7f5d932020-08-04 00:41:24 +0800535 with warnings_helper.check_warnings(("", ResourceWarning)):
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100536 del ss
Victor Stinnere0b75b72016-03-21 17:26:04 +0100537 self.assertEqual(wr(), None)
Antoine Pitrou9d543662010-04-23 23:10:32 +0000538
Antoine Pitroua468adc2010-09-14 14:43:44 +0000539 def test_wrapped_unconnected(self):
540 # Methods on an unconnected SSLSocket propagate the original
Andrew Svetlov0832af62012-12-18 23:10:48 +0200541 # OSError raise by the underlying socket object.
Antoine Pitroua468adc2010-09-14 14:43:44 +0000542 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200543 with test_wrap_socket(s) as ss:
Antoine Pitroue9bb4732013-01-12 21:56:56 +0100544 self.assertRaises(OSError, ss.recv, 1)
545 self.assertRaises(OSError, ss.recv_into, bytearray(b'x'))
546 self.assertRaises(OSError, ss.recvfrom, 1)
547 self.assertRaises(OSError, ss.recvfrom_into, bytearray(b'x'), 1)
548 self.assertRaises(OSError, ss.send, b'x')
549 self.assertRaises(OSError, ss.sendto, b'x', ('0.0.0.0', 0))
Serhiy Storchaka42b1d612018-12-06 22:36:55 +0200550 self.assertRaises(NotImplementedError, ss.dup)
Christian Heimes141c5e82018-02-24 21:10:57 +0100551 self.assertRaises(NotImplementedError, ss.sendmsg,
552 [b'x'], (), 0, ('0.0.0.0', 0))
Serhiy Storchaka42b1d612018-12-06 22:36:55 +0200553 self.assertRaises(NotImplementedError, ss.recvmsg, 100)
554 self.assertRaises(NotImplementedError, ss.recvmsg_into,
555 [bytearray(100)])
Antoine Pitroua468adc2010-09-14 14:43:44 +0000556
Antoine Pitrou40f08742010-04-24 22:04:40 +0000557 def test_timeout(self):
558 # Issue #8524: when creating an SSL socket, the timeout of the
559 # original socket should be retained.
560 for timeout in (None, 0.0, 5.0):
561 s = socket.socket(socket.AF_INET)
562 s.settimeout(timeout)
Christian Heimesd0486372016-09-10 23:23:33 +0200563 with test_wrap_socket(s) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100564 self.assertEqual(timeout, ss.gettimeout())
Antoine Pitrou40f08742010-04-24 22:04:40 +0000565
Christian Heimes2875c602021-04-19 07:27:10 +0200566 @ignore_deprecation
Christian Heimesd0486372016-09-10 23:23:33 +0200567 def test_errors_sslwrap(self):
Giampaolo Rodolà745ab382010-08-29 19:25:49 +0000568 sock = socket.socket()
Ezio Melottied3a7d22010-12-01 02:32:32 +0000569 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000570 "certfile must be specified",
571 ssl.wrap_socket, sock, keyfile=CERTFILE)
Ezio Melottied3a7d22010-12-01 02:32:32 +0000572 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000573 "certfile must be specified for server-side operations",
574 ssl.wrap_socket, sock, server_side=True)
Ezio Melottied3a7d22010-12-01 02:32:32 +0000575 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000576 "certfile must be specified for server-side operations",
Christian Heimesd0486372016-09-10 23:23:33 +0200577 ssl.wrap_socket, sock, server_side=True, certfile="")
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100578 with ssl.wrap_socket(sock, server_side=True, certfile=CERTFILE) as s:
579 self.assertRaisesRegex(ValueError, "can't connect in server-side mode",
Christian Heimesd0486372016-09-10 23:23:33 +0200580 s.connect, (HOST, 8080))
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200581 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000582 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000583 ssl.wrap_socket(sock, certfile=NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +0000584 self.assertEqual(cm.exception.errno, errno.ENOENT)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200585 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000586 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000587 ssl.wrap_socket(sock,
588 certfile=CERTFILE, keyfile=NONEXISTINGCERT)
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000589 self.assertEqual(cm.exception.errno, errno.ENOENT)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200590 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000591 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000592 ssl.wrap_socket(sock,
593 certfile=NONEXISTINGCERT, keyfile=NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +0000594 self.assertEqual(cm.exception.errno, errno.ENOENT)
Giampaolo Rodolà745ab382010-08-29 19:25:49 +0000595
Martin Panter3464ea22016-02-01 21:58:11 +0000596 def bad_cert_test(self, certfile):
597 """Check that trying to use the given client certificate fails"""
598 certfile = os.path.join(os.path.dirname(__file__) or os.curdir,
599 certfile)
600 sock = socket.socket()
601 self.addCleanup(sock.close)
602 with self.assertRaises(ssl.SSLError):
Christian Heimesd0486372016-09-10 23:23:33 +0200603 test_wrap_socket(sock,
Christian Heimesa170fa12017-09-15 20:27:30 +0200604 certfile=certfile)
Martin Panter3464ea22016-02-01 21:58:11 +0000605
606 def test_empty_cert(self):
607 """Wrapping with an empty cert file"""
608 self.bad_cert_test("nullcert.pem")
609
610 def test_malformed_cert(self):
611 """Wrapping with a badly formatted certificate (syntax error)"""
612 self.bad_cert_test("badcert.pem")
613
614 def test_malformed_key(self):
615 """Wrapping with a badly formatted key (syntax error)"""
616 self.bad_cert_test("badkey.pem")
617
Christian Heimes2875c602021-04-19 07:27:10 +0200618 @ignore_deprecation
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000619 def test_match_hostname(self):
620 def ok(cert, hostname):
621 ssl.match_hostname(cert, hostname)
622 def fail(cert, hostname):
623 self.assertRaises(ssl.CertificateError,
624 ssl.match_hostname, cert, hostname)
625
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100626 # -- Hostname matching --
627
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000628 cert = {'subject': ((('commonName', 'example.com'),),)}
629 ok(cert, 'example.com')
630 ok(cert, 'ExAmple.cOm')
631 fail(cert, 'www.example.com')
632 fail(cert, '.example.com')
633 fail(cert, 'example.org')
634 fail(cert, 'exampleXcom')
635
636 cert = {'subject': ((('commonName', '*.a.com'),),)}
637 ok(cert, 'foo.a.com')
638 fail(cert, 'bar.foo.a.com')
639 fail(cert, 'a.com')
640 fail(cert, 'Xa.com')
641 fail(cert, '.a.com')
642
Mandeep Singhede2ac92017-11-27 04:01:27 +0530643 # only match wildcards when they are the only thing
644 # in left-most segment
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000645 cert = {'subject': ((('commonName', 'f*.com'),),)}
Mandeep Singhede2ac92017-11-27 04:01:27 +0530646 fail(cert, 'foo.com')
647 fail(cert, 'f.com')
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000648 fail(cert, 'bar.com')
649 fail(cert, 'foo.a.com')
650 fail(cert, 'bar.foo.com')
651
Christian Heimes824f7f32013-08-17 00:54:47 +0200652 # NULL bytes are bad, CVE-2013-4073
653 cert = {'subject': ((('commonName',
654 'null.python.org\x00example.org'),),)}
655 ok(cert, 'null.python.org\x00example.org') # or raise an error?
656 fail(cert, 'example.org')
657 fail(cert, 'null.python.org')
658
Georg Brandl72c98d32013-10-27 07:16:53 +0100659 # error cases with wildcards
660 cert = {'subject': ((('commonName', '*.*.a.com'),),)}
661 fail(cert, 'bar.foo.a.com')
662 fail(cert, 'a.com')
663 fail(cert, 'Xa.com')
664 fail(cert, '.a.com')
665
666 cert = {'subject': ((('commonName', 'a.*.com'),),)}
667 fail(cert, 'a.foo.com')
668 fail(cert, 'a..com')
669 fail(cert, 'a.com')
670
671 # wildcard doesn't match IDNA prefix 'xn--'
672 idna = 'püthon.python.org'.encode("idna").decode("ascii")
673 cert = {'subject': ((('commonName', idna),),)}
674 ok(cert, idna)
675 cert = {'subject': ((('commonName', 'x*.python.org'),),)}
676 fail(cert, idna)
677 cert = {'subject': ((('commonName', 'xn--p*.python.org'),),)}
678 fail(cert, idna)
679
680 # wildcard in first fragment and IDNA A-labels in sequent fragments
681 # are supported.
682 idna = 'www*.pythön.org'.encode("idna").decode("ascii")
683 cert = {'subject': ((('commonName', idna),),)}
Mandeep Singhede2ac92017-11-27 04:01:27 +0530684 fail(cert, 'www.pythön.org'.encode("idna").decode("ascii"))
685 fail(cert, 'www1.pythön.org'.encode("idna").decode("ascii"))
Georg Brandl72c98d32013-10-27 07:16:53 +0100686 fail(cert, 'ftp.pythön.org'.encode("idna").decode("ascii"))
687 fail(cert, 'pythön.org'.encode("idna").decode("ascii"))
688
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000689 # Slightly fake real-world example
690 cert = {'notAfter': 'Jun 26 21:41:46 2011 GMT',
691 'subject': ((('commonName', 'linuxfrz.org'),),),
692 'subjectAltName': (('DNS', 'linuxfr.org'),
693 ('DNS', 'linuxfr.com'),
694 ('othername', '<unsupported>'))}
695 ok(cert, 'linuxfr.org')
696 ok(cert, 'linuxfr.com')
697 # Not a "DNS" entry
698 fail(cert, '<unsupported>')
699 # When there is a subjectAltName, commonName isn't used
700 fail(cert, 'linuxfrz.org')
701
702 # A pristine real-world example
703 cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT',
704 'subject': ((('countryName', 'US'),),
705 (('stateOrProvinceName', 'California'),),
706 (('localityName', 'Mountain View'),),
707 (('organizationName', 'Google Inc'),),
708 (('commonName', 'mail.google.com'),))}
709 ok(cert, 'mail.google.com')
710 fail(cert, 'gmail.com')
711 # Only commonName is considered
712 fail(cert, 'California')
713
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100714 # -- IPv4 matching --
715 cert = {'subject': ((('commonName', 'example.com'),),),
716 'subjectAltName': (('DNS', 'example.com'),
717 ('IP Address', '10.11.12.13'),
Christian Heimes477b1b22019-07-02 20:39:42 +0200718 ('IP Address', '14.15.16.17'),
719 ('IP Address', '127.0.0.1'))}
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100720 ok(cert, '10.11.12.13')
721 ok(cert, '14.15.16.17')
Christian Heimes477b1b22019-07-02 20:39:42 +0200722 # socket.inet_ntoa(socket.inet_aton('127.1')) == '127.0.0.1'
723 fail(cert, '127.1')
724 fail(cert, '14.15.16.17 ')
725 fail(cert, '14.15.16.17 extra data')
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100726 fail(cert, '14.15.16.18')
727 fail(cert, 'example.net')
728
729 # -- IPv6 matching --
Serhiy Storchaka16994912020-04-25 10:06:29 +0300730 if socket_helper.IPV6_ENABLED:
Christian Heimesaef12832018-02-24 14:35:56 +0100731 cert = {'subject': ((('commonName', 'example.com'),),),
732 'subjectAltName': (
733 ('DNS', 'example.com'),
734 ('IP Address', '2001:0:0:0:0:0:0:CAFE\n'),
735 ('IP Address', '2003:0:0:0:0:0:0:BABA\n'))}
736 ok(cert, '2001::cafe')
737 ok(cert, '2003::baba')
Christian Heimes477b1b22019-07-02 20:39:42 +0200738 fail(cert, '2003::baba ')
739 fail(cert, '2003::baba extra data')
Christian Heimesaef12832018-02-24 14:35:56 +0100740 fail(cert, '2003::bebe')
741 fail(cert, 'example.net')
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100742
743 # -- Miscellaneous --
744
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000745 # Neither commonName nor subjectAltName
746 cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT',
747 'subject': ((('countryName', 'US'),),
748 (('stateOrProvinceName', 'California'),),
749 (('localityName', 'Mountain View'),),
750 (('organizationName', 'Google Inc'),))}
751 fail(cert, 'mail.google.com')
752
Antoine Pitrou1c86b442011-05-06 15:19:49 +0200753 # No DNS entry in subjectAltName but a commonName
754 cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT',
755 'subject': ((('countryName', 'US'),),
756 (('stateOrProvinceName', 'California'),),
757 (('localityName', 'Mountain View'),),
758 (('commonName', 'mail.google.com'),)),
759 'subjectAltName': (('othername', 'blabla'), )}
760 ok(cert, 'mail.google.com')
761
762 # No DNS entry subjectAltName and no commonName
763 cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT',
764 'subject': ((('countryName', 'US'),),
765 (('stateOrProvinceName', 'California'),),
766 (('localityName', 'Mountain View'),),
767 (('organizationName', 'Google Inc'),)),
768 'subjectAltName': (('othername', 'blabla'),)}
769 fail(cert, 'google.com')
770
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000771 # Empty cert / no cert
772 self.assertRaises(ValueError, ssl.match_hostname, None, 'example.com')
773 self.assertRaises(ValueError, ssl.match_hostname, {}, 'example.com')
774
Antoine Pitrou636f93c2013-05-18 17:56:42 +0200775 # Issue #17980: avoid denials of service by refusing more than one
776 # wildcard per fragment.
Christian Heimesaef12832018-02-24 14:35:56 +0100777 cert = {'subject': ((('commonName', 'a*b.example.com'),),)}
778 with self.assertRaisesRegex(
779 ssl.CertificateError,
780 "partial wildcards in leftmost label are not supported"):
781 ssl.match_hostname(cert, 'axxb.example.com')
782
783 cert = {'subject': ((('commonName', 'www.*.example.com'),),)}
784 with self.assertRaisesRegex(
785 ssl.CertificateError,
786 "wildcard can only be present in the leftmost label"):
787 ssl.match_hostname(cert, 'www.sub.example.com')
788
789 cert = {'subject': ((('commonName', 'a*b*.example.com'),),)}
790 with self.assertRaisesRegex(
791 ssl.CertificateError,
792 "too many wildcards"):
793 ssl.match_hostname(cert, 'axxbxxc.example.com')
794
795 cert = {'subject': ((('commonName', '*'),),)}
796 with self.assertRaisesRegex(
797 ssl.CertificateError,
798 "sole wildcard without additional labels are not support"):
799 ssl.match_hostname(cert, 'host')
800
801 cert = {'subject': ((('commonName', '*.com'),),)}
802 with self.assertRaisesRegex(
803 ssl.CertificateError,
804 r"hostname 'com' doesn't match '\*.com'"):
805 ssl.match_hostname(cert, 'com')
806
807 # extra checks for _inet_paton()
808 for invalid in ['1', '', '1.2.3', '256.0.0.1', '127.0.0.1/24']:
809 with self.assertRaises(ValueError):
810 ssl._inet_paton(invalid)
811 for ipaddr in ['127.0.0.1', '192.168.0.1']:
812 self.assertTrue(ssl._inet_paton(ipaddr))
Serhiy Storchaka16994912020-04-25 10:06:29 +0300813 if socket_helper.IPV6_ENABLED:
Christian Heimesaef12832018-02-24 14:35:56 +0100814 for ipaddr in ['::1', '2001:db8:85a3::8a2e:370:7334']:
815 self.assertTrue(ssl._inet_paton(ipaddr))
Antoine Pitrou636f93c2013-05-18 17:56:42 +0200816
Antoine Pitroud5323212010-10-22 18:19:07 +0000817 def test_server_side(self):
818 # server_hostname doesn't work for server sockets
Christian Heimesa170fa12017-09-15 20:27:30 +0200819 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroud2eca372010-10-29 23:41:37 +0000820 with socket.socket() as sock:
821 self.assertRaises(ValueError, ctx.wrap_socket, sock, True,
822 server_hostname="some.hostname")
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000823
Antoine Pitroud6494802011-07-21 01:11:30 +0200824 def test_unknown_channel_binding(self):
825 # should raise ValueError for unknown type
Giampaolo Rodolaeb7e29f2019-04-09 00:34:02 +0200826 s = socket.create_server(('127.0.0.1', 0))
Antoine Pitroub1fdf472014-10-05 20:41:53 +0200827 c = socket.socket(socket.AF_INET)
828 c.connect(s.getsockname())
Christian Heimesd0486372016-09-10 23:23:33 +0200829 with test_wrap_socket(c, do_handshake_on_connect=False) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100830 with self.assertRaises(ValueError):
831 ss.get_channel_binding("unknown-type")
Antoine Pitroub1fdf472014-10-05 20:41:53 +0200832 s.close()
Antoine Pitroud6494802011-07-21 01:11:30 +0200833
834 @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES,
835 "'tls-unique' channel binding not available")
836 def test_tls_unique_channel_binding(self):
837 # unconnected should return None for known type
838 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200839 with test_wrap_socket(s) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100840 self.assertIsNone(ss.get_channel_binding("tls-unique"))
Antoine Pitroud6494802011-07-21 01:11:30 +0200841 # the same for server-side
842 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200843 with test_wrap_socket(s, server_side=True, certfile=CERTFILE) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100844 self.assertIsNone(ss.get_channel_binding("tls-unique"))
Antoine Pitroud6494802011-07-21 01:11:30 +0200845
Benjamin Peterson36f7b972013-01-10 14:16:20 -0600846 def test_dealloc_warn(self):
Christian Heimesd0486372016-09-10 23:23:33 +0200847 ss = test_wrap_socket(socket.socket(socket.AF_INET))
Benjamin Peterson36f7b972013-01-10 14:16:20 -0600848 r = repr(ss)
849 with self.assertWarns(ResourceWarning) as cm:
850 ss = None
851 support.gc_collect()
852 self.assertIn(r, str(cm.warning.args[0]))
853
Christian Heimes6d7ad132013-06-09 18:02:55 +0200854 def test_get_default_verify_paths(self):
855 paths = ssl.get_default_verify_paths()
856 self.assertEqual(len(paths), 6)
857 self.assertIsInstance(paths, ssl.DefaultVerifyPaths)
858
Hai Shia7f5d932020-08-04 00:41:24 +0800859 with os_helper.EnvironmentVarGuard() as env:
Christian Heimes6d7ad132013-06-09 18:02:55 +0200860 env["SSL_CERT_DIR"] = CAPATH
861 env["SSL_CERT_FILE"] = CERTFILE
862 paths = ssl.get_default_verify_paths()
863 self.assertEqual(paths.cafile, CERTFILE)
864 self.assertEqual(paths.capath, CAPATH)
865
Christian Heimes44109d72013-11-22 01:51:30 +0100866 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
867 def test_enum_certificates(self):
868 self.assertTrue(ssl.enum_certificates("CA"))
869 self.assertTrue(ssl.enum_certificates("ROOT"))
870
871 self.assertRaises(TypeError, ssl.enum_certificates)
872 self.assertRaises(WindowsError, ssl.enum_certificates, "")
873
Christian Heimesc2d65e12013-11-22 16:13:55 +0100874 trust_oids = set()
875 for storename in ("CA", "ROOT"):
876 store = ssl.enum_certificates(storename)
877 self.assertIsInstance(store, list)
878 for element in store:
879 self.assertIsInstance(element, tuple)
880 self.assertEqual(len(element), 3)
881 cert, enc, trust = element
882 self.assertIsInstance(cert, bytes)
883 self.assertIn(enc, {"x509_asn", "pkcs_7_asn"})
Christian Heimes915cd3f2019-09-09 18:06:55 +0200884 self.assertIsInstance(trust, (frozenset, set, bool))
885 if isinstance(trust, (frozenset, set)):
Christian Heimesc2d65e12013-11-22 16:13:55 +0100886 trust_oids.update(trust)
Christian Heimes44109d72013-11-22 01:51:30 +0100887
888 serverAuth = "1.3.6.1.5.5.7.3.1"
Christian Heimesc2d65e12013-11-22 16:13:55 +0100889 self.assertIn(serverAuth, trust_oids)
Christian Heimes6d7ad132013-06-09 18:02:55 +0200890
Christian Heimes46bebee2013-06-09 19:03:31 +0200891 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
Christian Heimes44109d72013-11-22 01:51:30 +0100892 def test_enum_crls(self):
893 self.assertTrue(ssl.enum_crls("CA"))
894 self.assertRaises(TypeError, ssl.enum_crls)
895 self.assertRaises(WindowsError, ssl.enum_crls, "")
Christian Heimes46bebee2013-06-09 19:03:31 +0200896
Christian Heimes44109d72013-11-22 01:51:30 +0100897 crls = ssl.enum_crls("CA")
898 self.assertIsInstance(crls, list)
899 for element in crls:
900 self.assertIsInstance(element, tuple)
901 self.assertEqual(len(element), 2)
902 self.assertIsInstance(element[0], bytes)
903 self.assertIn(element[1], {"x509_asn", "pkcs_7_asn"})
Christian Heimes46bebee2013-06-09 19:03:31 +0200904
Christian Heimes46bebee2013-06-09 19:03:31 +0200905
Christian Heimesa6bc95a2013-11-17 19:59:14 +0100906 def test_asn1object(self):
907 expected = (129, 'serverAuth', 'TLS Web Server Authentication',
908 '1.3.6.1.5.5.7.3.1')
909
910 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1')
911 self.assertEqual(val, expected)
912 self.assertEqual(val.nid, 129)
913 self.assertEqual(val.shortname, 'serverAuth')
914 self.assertEqual(val.longname, 'TLS Web Server Authentication')
915 self.assertEqual(val.oid, '1.3.6.1.5.5.7.3.1')
916 self.assertIsInstance(val, ssl._ASN1Object)
917 self.assertRaises(ValueError, ssl._ASN1Object, 'serverAuth')
918
919 val = ssl._ASN1Object.fromnid(129)
920 self.assertEqual(val, expected)
921 self.assertIsInstance(val, ssl._ASN1Object)
922 self.assertRaises(ValueError, ssl._ASN1Object.fromnid, -1)
Christian Heimes5398e1a2013-11-22 16:20:53 +0100923 with self.assertRaisesRegex(ValueError, "unknown NID 100000"):
924 ssl._ASN1Object.fromnid(100000)
Christian Heimesa6bc95a2013-11-17 19:59:14 +0100925 for i in range(1000):
926 try:
927 obj = ssl._ASN1Object.fromnid(i)
928 except ValueError:
929 pass
930 else:
931 self.assertIsInstance(obj.nid, int)
932 self.assertIsInstance(obj.shortname, str)
933 self.assertIsInstance(obj.longname, str)
934 self.assertIsInstance(obj.oid, (str, type(None)))
935
936 val = ssl._ASN1Object.fromname('TLS Web Server Authentication')
937 self.assertEqual(val, expected)
938 self.assertIsInstance(val, ssl._ASN1Object)
939 self.assertEqual(ssl._ASN1Object.fromname('serverAuth'), expected)
940 self.assertEqual(ssl._ASN1Object.fromname('1.3.6.1.5.5.7.3.1'),
941 expected)
Christian Heimes5398e1a2013-11-22 16:20:53 +0100942 with self.assertRaisesRegex(ValueError, "unknown object 'serverauth'"):
943 ssl._ASN1Object.fromname('serverauth')
Christian Heimesa6bc95a2013-11-17 19:59:14 +0100944
Christian Heimes72d28502013-11-23 13:56:58 +0100945 def test_purpose_enum(self):
946 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1')
947 self.assertIsInstance(ssl.Purpose.SERVER_AUTH, ssl._ASN1Object)
948 self.assertEqual(ssl.Purpose.SERVER_AUTH, val)
949 self.assertEqual(ssl.Purpose.SERVER_AUTH.nid, 129)
950 self.assertEqual(ssl.Purpose.SERVER_AUTH.shortname, 'serverAuth')
951 self.assertEqual(ssl.Purpose.SERVER_AUTH.oid,
952 '1.3.6.1.5.5.7.3.1')
953
954 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.2')
955 self.assertIsInstance(ssl.Purpose.CLIENT_AUTH, ssl._ASN1Object)
956 self.assertEqual(ssl.Purpose.CLIENT_AUTH, val)
957 self.assertEqual(ssl.Purpose.CLIENT_AUTH.nid, 130)
958 self.assertEqual(ssl.Purpose.CLIENT_AUTH.shortname, 'clientAuth')
959 self.assertEqual(ssl.Purpose.CLIENT_AUTH.oid,
960 '1.3.6.1.5.5.7.3.2')
961
Antoine Pitrou3e86ba42013-12-28 17:26:33 +0100962 def test_unsupported_dtls(self):
963 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
964 self.addCleanup(s.close)
965 with self.assertRaises(NotImplementedError) as cx:
Christian Heimesd0486372016-09-10 23:23:33 +0200966 test_wrap_socket(s, cert_reqs=ssl.CERT_NONE)
Antoine Pitrou3e86ba42013-12-28 17:26:33 +0100967 self.assertEqual(str(cx.exception), "only stream sockets are supported")
Christian Heimesa170fa12017-09-15 20:27:30 +0200968 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou3e86ba42013-12-28 17:26:33 +0100969 with self.assertRaises(NotImplementedError) as cx:
970 ctx.wrap_socket(s)
971 self.assertEqual(str(cx.exception), "only stream sockets are supported")
972
Antoine Pitrouc695c952014-04-28 20:57:36 +0200973 def cert_time_ok(self, timestring, timestamp):
974 self.assertEqual(ssl.cert_time_to_seconds(timestring), timestamp)
975
976 def cert_time_fail(self, timestring):
977 with self.assertRaises(ValueError):
978 ssl.cert_time_to_seconds(timestring)
979
980 @unittest.skipUnless(utc_offset(),
981 'local time needs to be different from UTC')
982 def test_cert_time_to_seconds_timezone(self):
983 # Issue #19940: ssl.cert_time_to_seconds() returns wrong
984 # results if local timezone is not UTC
985 self.cert_time_ok("May 9 00:00:00 2007 GMT", 1178668800.0)
986 self.cert_time_ok("Jan 5 09:34:43 2018 GMT", 1515144883.0)
987
988 def test_cert_time_to_seconds(self):
989 timestring = "Jan 5 09:34:43 2018 GMT"
990 ts = 1515144883.0
991 self.cert_time_ok(timestring, ts)
992 # accept keyword parameter, assert its name
993 self.assertEqual(ssl.cert_time_to_seconds(cert_time=timestring), ts)
994 # accept both %e and %d (space or zero generated by strftime)
995 self.cert_time_ok("Jan 05 09:34:43 2018 GMT", ts)
996 # case-insensitive
997 self.cert_time_ok("JaN 5 09:34:43 2018 GmT", ts)
998 self.cert_time_fail("Jan 5 09:34 2018 GMT") # no seconds
999 self.cert_time_fail("Jan 5 09:34:43 2018") # no GMT
1000 self.cert_time_fail("Jan 5 09:34:43 2018 UTC") # not GMT timezone
1001 self.cert_time_fail("Jan 35 09:34:43 2018 GMT") # invalid day
1002 self.cert_time_fail("Jon 5 09:34:43 2018 GMT") # invalid month
1003 self.cert_time_fail("Jan 5 24:00:00 2018 GMT") # invalid hour
1004 self.cert_time_fail("Jan 5 09:60:43 2018 GMT") # invalid minute
1005
1006 newyear_ts = 1230768000.0
1007 # leap seconds
1008 self.cert_time_ok("Dec 31 23:59:60 2008 GMT", newyear_ts)
1009 # same timestamp
1010 self.cert_time_ok("Jan 1 00:00:00 2009 GMT", newyear_ts)
1011
1012 self.cert_time_ok("Jan 5 09:34:59 2018 GMT", 1515144899)
1013 # allow 60th second (even if it is not a leap second)
1014 self.cert_time_ok("Jan 5 09:34:60 2018 GMT", 1515144900)
1015 # allow 2nd leap second for compatibility with time.strptime()
1016 self.cert_time_ok("Jan 5 09:34:61 2018 GMT", 1515144901)
1017 self.cert_time_fail("Jan 5 09:34:62 2018 GMT") # invalid seconds
1018
Mike53f7a7c2017-12-14 14:04:53 +03001019 # no special treatment for the special value:
Antoine Pitrouc695c952014-04-28 20:57:36 +02001020 # 99991231235959Z (rfc 5280)
1021 self.cert_time_ok("Dec 31 23:59:59 9999 GMT", 253402300799.0)
1022
1023 @support.run_with_locale('LC_ALL', '')
1024 def test_cert_time_to_seconds_locale(self):
1025 # `cert_time_to_seconds()` should be locale independent
1026
1027 def local_february_name():
1028 return time.strftime('%b', (1, 2, 3, 4, 5, 6, 0, 0, 0))
1029
1030 if local_february_name().lower() == 'feb':
1031 self.skipTest("locale-specific month name needs to be "
1032 "different from C locale")
1033
1034 # locale-independent
1035 self.cert_time_ok("Feb 9 00:00:00 2007 GMT", 1170979200.0)
1036 self.cert_time_fail(local_february_name() + " 9 00:00:00 2007 GMT")
1037
Martin Panter3840b2a2016-03-27 01:53:46 +00001038 def test_connect_ex_error(self):
1039 server = socket.socket(socket.AF_INET)
1040 self.addCleanup(server.close)
Serhiy Storchaka16994912020-04-25 10:06:29 +03001041 port = socket_helper.bind_port(server) # Reserve port but don't listen
Christian Heimesd0486372016-09-10 23:23:33 +02001042 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001043 cert_reqs=ssl.CERT_REQUIRED)
1044 self.addCleanup(s.close)
1045 rc = s.connect_ex((HOST, port))
1046 # Issue #19919: Windows machines or VMs hosted on Windows
1047 # machines sometimes return EWOULDBLOCK.
1048 errors = (
1049 errno.ECONNREFUSED, errno.EHOSTUNREACH, errno.ETIMEDOUT,
1050 errno.EWOULDBLOCK,
1051 )
1052 self.assertIn(rc, errors)
1053
Christian Heimes89d15502021-04-19 06:55:30 +02001054 def test_read_write_zero(self):
1055 # empty reads and writes now work, bpo-42854, bpo-31711
1056 client_context, server_context, hostname = testing_context()
1057 server = ThreadedEchoServer(context=server_context)
1058 with server:
1059 with client_context.wrap_socket(socket.socket(),
1060 server_hostname=hostname) as s:
1061 s.connect((HOST, server.port))
1062 self.assertEqual(s.recv(0), b"")
1063 self.assertEqual(s.send(b""), 0)
1064
Christian Heimesa6bc95a2013-11-17 19:59:14 +01001065
Antoine Pitrou152efa22010-05-16 18:19:27 +00001066class ContextTests(unittest.TestCase):
1067
1068 def test_constructor(self):
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01001069 for protocol in PROTOCOLS:
Christian Heimes2875c602021-04-19 07:27:10 +02001070 with warnings_helper.check_warnings():
1071 ctx = ssl.SSLContext(protocol)
1072 self.assertEqual(ctx.protocol, protocol)
1073 with warnings_helper.check_warnings():
1074 ctx = ssl.SSLContext()
Christian Heimes598894f2016-09-05 23:19:05 +02001075 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001076 self.assertRaises(ValueError, ssl.SSLContext, -1)
1077 self.assertRaises(ValueError, ssl.SSLContext, 42)
1078
Antoine Pitrou152efa22010-05-16 18:19:27 +00001079 def test_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001080 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001081 ctx.set_ciphers("ALL")
1082 ctx.set_ciphers("DEFAULT")
Ezio Melottied3a7d22010-12-01 02:32:32 +00001083 with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
Antoine Pitrou30474062010-05-16 23:46:26 +00001084 ctx.set_ciphers("^$:,;?*'dorothyx")
Antoine Pitrou152efa22010-05-16 18:19:27 +00001085
Christian Heimes892d66e2018-01-29 14:10:18 +01001086 @unittest.skipUnless(PY_SSL_DEFAULT_CIPHERS == 1,
1087 "Test applies only to Python default ciphers")
1088 def test_python_ciphers(self):
1089 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1090 ciphers = ctx.get_ciphers()
1091 for suite in ciphers:
1092 name = suite['name']
1093 self.assertNotIn("PSK", name)
1094 self.assertNotIn("SRP", name)
1095 self.assertNotIn("MD5", name)
1096 self.assertNotIn("RC4", name)
1097 self.assertNotIn("3DES", name)
1098
Christian Heimes25bfcd52016-09-06 00:04:45 +02001099 def test_get_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001100 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesea9b2dc2016-09-06 10:45:44 +02001101 ctx.set_ciphers('AESGCM')
Christian Heimes25bfcd52016-09-06 00:04:45 +02001102 names = set(d['name'] for d in ctx.get_ciphers())
Christian Heimes582282b2016-09-06 11:27:25 +02001103 self.assertIn('AES256-GCM-SHA384', names)
1104 self.assertIn('AES128-GCM-SHA256', names)
Christian Heimes25bfcd52016-09-06 00:04:45 +02001105
Antoine Pitroub5218772010-05-21 09:56:06 +00001106 def test_options(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001107 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Benjamin Petersona9dcdab2015-11-11 22:38:41 -08001108 # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value
Christian Heimes598894f2016-09-05 23:19:05 +02001109 default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
Christian Heimes358cfd42016-09-10 22:43:48 +02001110 # SSLContext also enables these by default
1111 default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE |
Christian Heimes05d9fe32018-02-27 08:55:39 +01001112 OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE |
Christian Heimes6f37ebc2021-04-09 17:59:21 +02001113 OP_ENABLE_MIDDLEBOX_COMPAT |
1114 OP_IGNORE_UNEXPECTED_EOF)
Christian Heimes598894f2016-09-05 23:19:05 +02001115 self.assertEqual(default, ctx.options)
Christian Heimes2875c602021-04-19 07:27:10 +02001116 with warnings_helper.check_warnings():
1117 ctx.options |= ssl.OP_NO_TLSv1
Christian Heimes598894f2016-09-05 23:19:05 +02001118 self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options)
Christian Heimes2875c602021-04-19 07:27:10 +02001119 with warnings_helper.check_warnings():
1120 ctx.options = (ctx.options & ~ssl.OP_NO_TLSv1)
Christian Heimes39258d32021-04-17 11:36:35 +02001121 self.assertEqual(default, ctx.options)
1122 ctx.options = 0
1123 # Ubuntu has OP_NO_SSLv3 forced on by default
1124 self.assertEqual(0, ctx.options & ~ssl.OP_NO_SSLv3)
Antoine Pitroub5218772010-05-21 09:56:06 +00001125
Christian Heimesa170fa12017-09-15 20:27:30 +02001126 def test_verify_mode_protocol(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001127 with warnings_helper.check_warnings():
1128 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001129 # Default value
1130 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1131 ctx.verify_mode = ssl.CERT_OPTIONAL
1132 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1133 ctx.verify_mode = ssl.CERT_REQUIRED
1134 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1135 ctx.verify_mode = ssl.CERT_NONE
1136 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1137 with self.assertRaises(TypeError):
1138 ctx.verify_mode = None
1139 with self.assertRaises(ValueError):
1140 ctx.verify_mode = 42
1141
Christian Heimesa170fa12017-09-15 20:27:30 +02001142 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1143 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1144 self.assertFalse(ctx.check_hostname)
1145
1146 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1147 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1148 self.assertTrue(ctx.check_hostname)
1149
Christian Heimes61d478c2018-01-27 15:51:38 +01001150 def test_hostname_checks_common_name(self):
1151 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1152 self.assertTrue(ctx.hostname_checks_common_name)
1153 if ssl.HAS_NEVER_CHECK_COMMON_NAME:
1154 ctx.hostname_checks_common_name = True
1155 self.assertTrue(ctx.hostname_checks_common_name)
1156 ctx.hostname_checks_common_name = False
1157 self.assertFalse(ctx.hostname_checks_common_name)
1158 ctx.hostname_checks_common_name = True
1159 self.assertTrue(ctx.hostname_checks_common_name)
1160 else:
1161 with self.assertRaises(AttributeError):
1162 ctx.hostname_checks_common_name = True
Christian Heimesa170fa12017-09-15 20:27:30 +02001163
Christian Heimes2875c602021-04-19 07:27:10 +02001164 @ignore_deprecation
Christian Heimes698dde12018-02-27 11:54:43 +01001165 def test_min_max_version(self):
1166 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimes34de2d32019-01-18 16:09:30 +01001167 # OpenSSL default is MINIMUM_SUPPORTED, however some vendors like
1168 # Fedora override the setting to TLS 1.0.
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001169 minimum_range = {
1170 # stock OpenSSL
1171 ssl.TLSVersion.MINIMUM_SUPPORTED,
1172 # Fedora 29 uses TLS 1.0 by default
1173 ssl.TLSVersion.TLSv1,
1174 # RHEL 8 uses TLS 1.2 by default
1175 ssl.TLSVersion.TLSv1_2
1176 }
torsava34864d12019-12-02 17:15:42 +01001177 maximum_range = {
1178 # stock OpenSSL
1179 ssl.TLSVersion.MAXIMUM_SUPPORTED,
1180 # Fedora 32 uses TLS 1.3 by default
1181 ssl.TLSVersion.TLSv1_3
1182 }
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001183
Christian Heimes34de2d32019-01-18 16:09:30 +01001184 self.assertIn(
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001185 ctx.minimum_version, minimum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001186 )
torsava34864d12019-12-02 17:15:42 +01001187 self.assertIn(
1188 ctx.maximum_version, maximum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001189 )
1190
1191 ctx.minimum_version = ssl.TLSVersion.TLSv1_1
1192 ctx.maximum_version = ssl.TLSVersion.TLSv1_2
1193 self.assertEqual(
1194 ctx.minimum_version, ssl.TLSVersion.TLSv1_1
1195 )
1196 self.assertEqual(
1197 ctx.maximum_version, ssl.TLSVersion.TLSv1_2
1198 )
1199
1200 ctx.minimum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1201 ctx.maximum_version = ssl.TLSVersion.TLSv1
1202 self.assertEqual(
1203 ctx.minimum_version, ssl.TLSVersion.MINIMUM_SUPPORTED
1204 )
1205 self.assertEqual(
1206 ctx.maximum_version, ssl.TLSVersion.TLSv1
1207 )
1208
1209 ctx.maximum_version = ssl.TLSVersion.MAXIMUM_SUPPORTED
1210 self.assertEqual(
1211 ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED
1212 )
1213
1214 ctx.maximum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1215 self.assertIn(
1216 ctx.maximum_version,
1217 {ssl.TLSVersion.TLSv1, ssl.TLSVersion.SSLv3}
1218 )
1219
1220 ctx.minimum_version = ssl.TLSVersion.MAXIMUM_SUPPORTED
1221 self.assertIn(
1222 ctx.minimum_version,
1223 {ssl.TLSVersion.TLSv1_2, ssl.TLSVersion.TLSv1_3}
1224 )
1225
1226 with self.assertRaises(ValueError):
1227 ctx.minimum_version = 42
1228
1229 ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_1)
1230
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001231 self.assertIn(
1232 ctx.minimum_version, minimum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001233 )
1234 self.assertEqual(
1235 ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED
1236 )
1237 with self.assertRaises(ValueError):
1238 ctx.minimum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1239 with self.assertRaises(ValueError):
1240 ctx.maximum_version = ssl.TLSVersion.TLSv1
1241
1242
matthewhughes9348e836bb2020-07-17 09:59:15 +01001243 @unittest.skipUnless(
1244 hasattr(ssl.SSLContext, 'security_level'),
1245 "requires OpenSSL >= 1.1.0"
1246 )
1247 def test_security_level(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001248 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
matthewhughes9348e836bb2020-07-17 09:59:15 +01001249 # The default security callback allows for levels between 0-5
1250 # with OpenSSL defaulting to 1, however some vendors override the
1251 # default value (e.g. Debian defaults to 2)
1252 security_level_range = {
1253 0,
1254 1, # OpenSSL default
1255 2, # Debian
1256 3,
1257 4,
1258 5,
1259 }
1260 self.assertIn(ctx.security_level, security_level_range)
1261
Christian Heimes22587792013-11-21 23:56:13 +01001262 def test_verify_flags(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001263 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Benjamin Peterson990fcaa2015-03-04 22:49:41 -05001264 # default value
1265 tf = getattr(ssl, "VERIFY_X509_TRUSTED_FIRST", 0)
1266 self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT | tf)
Christian Heimes22587792013-11-21 23:56:13 +01001267 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF
1268 self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_LEAF)
1269 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_CHAIN
1270 self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_CHAIN)
1271 ctx.verify_flags = ssl.VERIFY_DEFAULT
1272 self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT)
Chris Burre0b4aa02021-03-18 09:24:01 +01001273 ctx.verify_flags = ssl.VERIFY_ALLOW_PROXY_CERTS
1274 self.assertEqual(ctx.verify_flags, ssl.VERIFY_ALLOW_PROXY_CERTS)
Christian Heimes22587792013-11-21 23:56:13 +01001275 # supports any value
1276 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT
1277 self.assertEqual(ctx.verify_flags,
1278 ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT)
1279 with self.assertRaises(TypeError):
1280 ctx.verify_flags = None
1281
Antoine Pitrou152efa22010-05-16 18:19:27 +00001282 def test_load_cert_chain(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001283 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001284 # Combined key and cert in a single file
Benjamin Peterson1ea070e2014-11-03 21:05:01 -05001285 ctx.load_cert_chain(CERTFILE, keyfile=None)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001286 ctx.load_cert_chain(CERTFILE, keyfile=CERTFILE)
1287 self.assertRaises(TypeError, ctx.load_cert_chain, keyfile=CERTFILE)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001288 with self.assertRaises(OSError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001289 ctx.load_cert_chain(NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +00001290 self.assertEqual(cm.exception.errno, errno.ENOENT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001291 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001292 ctx.load_cert_chain(BADCERT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001293 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001294 ctx.load_cert_chain(EMPTYCERT)
1295 # Separate key and cert
Christian Heimesa170fa12017-09-15 20:27:30 +02001296 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001297 ctx.load_cert_chain(ONLYCERT, ONLYKEY)
1298 ctx.load_cert_chain(certfile=ONLYCERT, keyfile=ONLYKEY)
1299 ctx.load_cert_chain(certfile=BYTES_ONLYCERT, keyfile=BYTES_ONLYKEY)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001300 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001301 ctx.load_cert_chain(ONLYCERT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001302 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001303 ctx.load_cert_chain(ONLYKEY)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001304 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001305 ctx.load_cert_chain(certfile=ONLYKEY, keyfile=ONLYCERT)
1306 # Mismatching key and cert
Christian Heimesa170fa12017-09-15 20:27:30 +02001307 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001308 with self.assertRaisesRegex(ssl.SSLError, "key values mismatch"):
Martin Panter3d81d932016-01-14 09:36:00 +00001309 ctx.load_cert_chain(CAFILE_CACERT, ONLYKEY)
Antoine Pitrou4fd1e6a2011-08-25 14:39:44 +02001310 # Password protected key and cert
1311 ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD)
1312 ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD.encode())
1313 ctx.load_cert_chain(CERTFILE_PROTECTED,
1314 password=bytearray(KEY_PASSWORD.encode()))
1315 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD)
1316 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD.encode())
1317 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED,
1318 bytearray(KEY_PASSWORD.encode()))
1319 with self.assertRaisesRegex(TypeError, "should be a string"):
1320 ctx.load_cert_chain(CERTFILE_PROTECTED, password=True)
1321 with self.assertRaises(ssl.SSLError):
1322 ctx.load_cert_chain(CERTFILE_PROTECTED, password="badpass")
1323 with self.assertRaisesRegex(ValueError, "cannot be longer"):
1324 # openssl has a fixed limit on the password buffer.
1325 # PEM_BUFSIZE is generally set to 1kb.
1326 # Return a string larger than this.
1327 ctx.load_cert_chain(CERTFILE_PROTECTED, password=b'a' * 102400)
1328 # Password callback
1329 def getpass_unicode():
1330 return KEY_PASSWORD
1331 def getpass_bytes():
1332 return KEY_PASSWORD.encode()
1333 def getpass_bytearray():
1334 return bytearray(KEY_PASSWORD.encode())
1335 def getpass_badpass():
1336 return "badpass"
1337 def getpass_huge():
1338 return b'a' * (1024 * 1024)
1339 def getpass_bad_type():
1340 return 9
1341 def getpass_exception():
1342 raise Exception('getpass error')
1343 class GetPassCallable:
1344 def __call__(self):
1345 return KEY_PASSWORD
1346 def getpass(self):
1347 return KEY_PASSWORD
1348 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_unicode)
1349 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytes)
1350 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytearray)
1351 ctx.load_cert_chain(CERTFILE_PROTECTED, password=GetPassCallable())
1352 ctx.load_cert_chain(CERTFILE_PROTECTED,
1353 password=GetPassCallable().getpass)
1354 with self.assertRaises(ssl.SSLError):
1355 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_badpass)
1356 with self.assertRaisesRegex(ValueError, "cannot be longer"):
1357 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_huge)
1358 with self.assertRaisesRegex(TypeError, "must return a string"):
1359 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bad_type)
1360 with self.assertRaisesRegex(Exception, "getpass error"):
1361 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_exception)
1362 # Make sure the password function isn't called if it isn't needed
1363 ctx.load_cert_chain(CERTFILE, password=getpass_exception)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001364
1365 def test_load_verify_locations(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001366 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001367 ctx.load_verify_locations(CERTFILE)
1368 ctx.load_verify_locations(cafile=CERTFILE, capath=None)
1369 ctx.load_verify_locations(BYTES_CERTFILE)
1370 ctx.load_verify_locations(cafile=BYTES_CERTFILE, capath=None)
1371 self.assertRaises(TypeError, ctx.load_verify_locations)
Christian Heimesefff7062013-11-21 03:35:02 +01001372 self.assertRaises(TypeError, ctx.load_verify_locations, None, None, None)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001373 with self.assertRaises(OSError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001374 ctx.load_verify_locations(NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +00001375 self.assertEqual(cm.exception.errno, errno.ENOENT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001376 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001377 ctx.load_verify_locations(BADCERT)
1378 ctx.load_verify_locations(CERTFILE, CAPATH)
1379 ctx.load_verify_locations(CERTFILE, capath=BYTES_CAPATH)
1380
Victor Stinner80f75e62011-01-29 11:31:20 +00001381 # Issue #10989: crash if the second argument type is invalid
1382 self.assertRaises(TypeError, ctx.load_verify_locations, None, True)
1383
Christian Heimesefff7062013-11-21 03:35:02 +01001384 def test_load_verify_cadata(self):
1385 # test cadata
1386 with open(CAFILE_CACERT) as f:
1387 cacert_pem = f.read()
1388 cacert_der = ssl.PEM_cert_to_DER_cert(cacert_pem)
1389 with open(CAFILE_NEURONIO) as f:
1390 neuronio_pem = f.read()
1391 neuronio_der = ssl.PEM_cert_to_DER_cert(neuronio_pem)
1392
1393 # test PEM
Christian Heimesa170fa12017-09-15 20:27:30 +02001394 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001395 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 0)
1396 ctx.load_verify_locations(cadata=cacert_pem)
1397 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 1)
1398 ctx.load_verify_locations(cadata=neuronio_pem)
1399 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1400 # cert already in hash table
1401 ctx.load_verify_locations(cadata=neuronio_pem)
1402 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1403
1404 # combined
Christian Heimesa170fa12017-09-15 20:27:30 +02001405 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001406 combined = "\n".join((cacert_pem, neuronio_pem))
1407 ctx.load_verify_locations(cadata=combined)
1408 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1409
1410 # with junk around the certs
Christian Heimesa170fa12017-09-15 20:27:30 +02001411 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001412 combined = ["head", cacert_pem, "other", neuronio_pem, "again",
1413 neuronio_pem, "tail"]
1414 ctx.load_verify_locations(cadata="\n".join(combined))
1415 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1416
1417 # test DER
Christian Heimesa170fa12017-09-15 20:27:30 +02001418 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001419 ctx.load_verify_locations(cadata=cacert_der)
1420 ctx.load_verify_locations(cadata=neuronio_der)
1421 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1422 # cert already in hash table
1423 ctx.load_verify_locations(cadata=cacert_der)
1424 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1425
1426 # combined
Christian Heimesa170fa12017-09-15 20:27:30 +02001427 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001428 combined = b"".join((cacert_der, neuronio_der))
1429 ctx.load_verify_locations(cadata=combined)
1430 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1431
1432 # error cases
Christian Heimesa170fa12017-09-15 20:27:30 +02001433 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001434 self.assertRaises(TypeError, ctx.load_verify_locations, cadata=object)
1435
Christian Heimesb9ad88b2021-04-23 13:51:40 +02001436 with self.assertRaisesRegex(
1437 ssl.SSLError,
1438 "no start line: cadata does not contain a certificate"
1439 ):
Christian Heimesefff7062013-11-21 03:35:02 +01001440 ctx.load_verify_locations(cadata="broken")
Christian Heimesb9ad88b2021-04-23 13:51:40 +02001441 with self.assertRaisesRegex(
1442 ssl.SSLError,
1443 "not enough data: cadata does not contain a certificate"
1444 ):
Christian Heimesefff7062013-11-21 03:35:02 +01001445 ctx.load_verify_locations(cadata=b"broken")
1446
Paul Monsonf3550692019-06-19 13:09:54 -07001447 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001448 def test_load_dh_params(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001449 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001450 ctx.load_dh_params(DHFILE)
1451 if os.name != 'nt':
1452 ctx.load_dh_params(BYTES_DHFILE)
1453 self.assertRaises(TypeError, ctx.load_dh_params)
1454 self.assertRaises(TypeError, ctx.load_dh_params, None)
1455 with self.assertRaises(FileNotFoundError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001456 ctx.load_dh_params(NONEXISTINGCERT)
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001457 self.assertEqual(cm.exception.errno, errno.ENOENT)
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001458 with self.assertRaises(ssl.SSLError) as cm:
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001459 ctx.load_dh_params(CERTFILE)
1460
Antoine Pitroub0182c82010-10-12 20:09:02 +00001461 def test_session_stats(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001462 for proto in {ssl.PROTOCOL_TLS_CLIENT, ssl.PROTOCOL_TLS_SERVER}:
Antoine Pitroub0182c82010-10-12 20:09:02 +00001463 ctx = ssl.SSLContext(proto)
1464 self.assertEqual(ctx.session_stats(), {
1465 'number': 0,
1466 'connect': 0,
1467 'connect_good': 0,
1468 'connect_renegotiate': 0,
1469 'accept': 0,
1470 'accept_good': 0,
1471 'accept_renegotiate': 0,
1472 'hits': 0,
1473 'misses': 0,
1474 'timeouts': 0,
1475 'cache_full': 0,
1476 })
1477
Antoine Pitrou664c2d12010-11-17 20:29:42 +00001478 def test_set_default_verify_paths(self):
1479 # There's not much we can do to test that it acts as expected,
1480 # so just check it doesn't crash or raise an exception.
Christian Heimesa170fa12017-09-15 20:27:30 +02001481 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou664c2d12010-11-17 20:29:42 +00001482 ctx.set_default_verify_paths()
1483
Antoine Pitrou501da612011-12-21 09:27:41 +01001484 @unittest.skipUnless(ssl.HAS_ECDH, "ECDH disabled on this OpenSSL build")
Antoine Pitrou923df6f2011-12-19 17:16:51 +01001485 def test_set_ecdh_curve(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001486 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou923df6f2011-12-19 17:16:51 +01001487 ctx.set_ecdh_curve("prime256v1")
1488 ctx.set_ecdh_curve(b"prime256v1")
1489 self.assertRaises(TypeError, ctx.set_ecdh_curve)
1490 self.assertRaises(TypeError, ctx.set_ecdh_curve, None)
1491 self.assertRaises(ValueError, ctx.set_ecdh_curve, "foo")
1492 self.assertRaises(ValueError, ctx.set_ecdh_curve, b"foo")
1493
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001494 def test_sni_callback(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001495 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001496
1497 # set_servername_callback expects a callable, or None
1498 self.assertRaises(TypeError, ctx.set_servername_callback)
1499 self.assertRaises(TypeError, ctx.set_servername_callback, 4)
1500 self.assertRaises(TypeError, ctx.set_servername_callback, "")
1501 self.assertRaises(TypeError, ctx.set_servername_callback, ctx)
1502
1503 def dummycallback(sock, servername, ctx):
1504 pass
1505 ctx.set_servername_callback(None)
1506 ctx.set_servername_callback(dummycallback)
1507
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001508 def test_sni_callback_refcycle(self):
1509 # Reference cycles through the servername callback are detected
1510 # and cleared.
Christian Heimesa170fa12017-09-15 20:27:30 +02001511 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001512 def dummycallback(sock, servername, ctx, cycle=ctx):
1513 pass
1514 ctx.set_servername_callback(dummycallback)
1515 wr = weakref.ref(ctx)
1516 del ctx, dummycallback
1517 gc.collect()
1518 self.assertIs(wr(), None)
1519
Christian Heimes9a5395a2013-06-17 15:44:12 +02001520 def test_cert_store_stats(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001521 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001522 self.assertEqual(ctx.cert_store_stats(),
1523 {'x509_ca': 0, 'crl': 0, 'x509': 0})
1524 ctx.load_cert_chain(CERTFILE)
1525 self.assertEqual(ctx.cert_store_stats(),
1526 {'x509_ca': 0, 'crl': 0, 'x509': 0})
1527 ctx.load_verify_locations(CERTFILE)
1528 self.assertEqual(ctx.cert_store_stats(),
1529 {'x509_ca': 0, 'crl': 0, 'x509': 1})
Martin Panterb55f8b72016-01-14 12:53:56 +00001530 ctx.load_verify_locations(CAFILE_CACERT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001531 self.assertEqual(ctx.cert_store_stats(),
1532 {'x509_ca': 1, 'crl': 0, 'x509': 2})
1533
1534 def test_get_ca_certs(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001535 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001536 self.assertEqual(ctx.get_ca_certs(), [])
1537 # CERTFILE is not flagged as X509v3 Basic Constraints: CA:TRUE
1538 ctx.load_verify_locations(CERTFILE)
1539 self.assertEqual(ctx.get_ca_certs(), [])
Martin Panterb55f8b72016-01-14 12:53:56 +00001540 # but CAFILE_CACERT is a CA cert
1541 ctx.load_verify_locations(CAFILE_CACERT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001542 self.assertEqual(ctx.get_ca_certs(),
1543 [{'issuer': ((('organizationName', 'Root CA'),),
1544 (('organizationalUnitName', 'http://www.cacert.org'),),
1545 (('commonName', 'CA Cert Signing Authority'),),
1546 (('emailAddress', 'support@cacert.org'),)),
Christian Heimesd37b74f2021-04-19 08:31:29 +02001547 'notAfter': 'Mar 29 12:29:49 2033 GMT',
1548 'notBefore': 'Mar 30 12:29:49 2003 GMT',
Christian Heimes9a5395a2013-06-17 15:44:12 +02001549 'serialNumber': '00',
Christian Heimesbd3a7f92013-11-21 03:40:15 +01001550 'crlDistributionPoints': ('https://www.cacert.org/revoke.crl',),
Christian Heimes9a5395a2013-06-17 15:44:12 +02001551 'subject': ((('organizationName', 'Root CA'),),
1552 (('organizationalUnitName', 'http://www.cacert.org'),),
1553 (('commonName', 'CA Cert Signing Authority'),),
1554 (('emailAddress', 'support@cacert.org'),)),
1555 'version': 3}])
1556
Martin Panterb55f8b72016-01-14 12:53:56 +00001557 with open(CAFILE_CACERT) as f:
Christian Heimes9a5395a2013-06-17 15:44:12 +02001558 pem = f.read()
1559 der = ssl.PEM_cert_to_DER_cert(pem)
1560 self.assertEqual(ctx.get_ca_certs(True), [der])
1561
Christian Heimes72d28502013-11-23 13:56:58 +01001562 def test_load_default_certs(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001563 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001564 ctx.load_default_certs()
1565
Christian Heimesa170fa12017-09-15 20:27:30 +02001566 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001567 ctx.load_default_certs(ssl.Purpose.SERVER_AUTH)
1568 ctx.load_default_certs()
1569
Christian Heimesa170fa12017-09-15 20:27:30 +02001570 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001571 ctx.load_default_certs(ssl.Purpose.CLIENT_AUTH)
1572
Christian Heimesa170fa12017-09-15 20:27:30 +02001573 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001574 self.assertRaises(TypeError, ctx.load_default_certs, None)
1575 self.assertRaises(TypeError, ctx.load_default_certs, 'SERVER_AUTH')
1576
Benjamin Peterson91244e02014-10-03 18:17:15 -04001577 @unittest.skipIf(sys.platform == "win32", "not-Windows specific")
Benjamin Peterson5915b0f2014-10-03 17:27:05 -04001578 def test_load_default_certs_env(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001579 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Hai Shia7f5d932020-08-04 00:41:24 +08001580 with os_helper.EnvironmentVarGuard() as env:
Benjamin Peterson5915b0f2014-10-03 17:27:05 -04001581 env["SSL_CERT_DIR"] = CAPATH
1582 env["SSL_CERT_FILE"] = CERTFILE
1583 ctx.load_default_certs()
1584 self.assertEqual(ctx.cert_store_stats(), {"crl": 0, "x509": 1, "x509_ca": 0})
1585
Benjamin Peterson91244e02014-10-03 18:17:15 -04001586 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
Steve Dower68d663c2017-07-17 11:15:48 +02001587 @unittest.skipIf(hasattr(sys, "gettotalrefcount"), "Debug build does not share environment between CRTs")
Benjamin Peterson91244e02014-10-03 18:17:15 -04001588 def test_load_default_certs_env_windows(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001589 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Benjamin Peterson91244e02014-10-03 18:17:15 -04001590 ctx.load_default_certs()
1591 stats = ctx.cert_store_stats()
1592
Christian Heimesa170fa12017-09-15 20:27:30 +02001593 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Hai Shia7f5d932020-08-04 00:41:24 +08001594 with os_helper.EnvironmentVarGuard() as env:
Benjamin Peterson91244e02014-10-03 18:17:15 -04001595 env["SSL_CERT_DIR"] = CAPATH
1596 env["SSL_CERT_FILE"] = CERTFILE
1597 ctx.load_default_certs()
1598 stats["x509"] += 1
1599 self.assertEqual(ctx.cert_store_stats(), stats)
1600
Christian Heimes358cfd42016-09-10 22:43:48 +02001601 def _assert_context_options(self, ctx):
1602 self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
1603 if OP_NO_COMPRESSION != 0:
1604 self.assertEqual(ctx.options & OP_NO_COMPRESSION,
1605 OP_NO_COMPRESSION)
1606 if OP_SINGLE_DH_USE != 0:
1607 self.assertEqual(ctx.options & OP_SINGLE_DH_USE,
1608 OP_SINGLE_DH_USE)
1609 if OP_SINGLE_ECDH_USE != 0:
1610 self.assertEqual(ctx.options & OP_SINGLE_ECDH_USE,
1611 OP_SINGLE_ECDH_USE)
1612 if OP_CIPHER_SERVER_PREFERENCE != 0:
1613 self.assertEqual(ctx.options & OP_CIPHER_SERVER_PREFERENCE,
1614 OP_CIPHER_SERVER_PREFERENCE)
1615
Christian Heimes4c05b472013-11-23 15:58:30 +01001616 def test_create_default_context(self):
1617 ctx = ssl.create_default_context()
Christian Heimes358cfd42016-09-10 22:43:48 +02001618
Christian Heimes2875c602021-04-19 07:27:10 +02001619 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes4c05b472013-11-23 15:58:30 +01001620 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001621 self.assertTrue(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001622 self._assert_context_options(ctx)
1623
Christian Heimes4c05b472013-11-23 15:58:30 +01001624 with open(SIGNING_CA) as f:
1625 cadata = f.read()
1626 ctx = ssl.create_default_context(cafile=SIGNING_CA, capath=CAPATH,
1627 cadata=cadata)
Christian Heimes2875c602021-04-19 07:27:10 +02001628 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes4c05b472013-11-23 15:58:30 +01001629 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes358cfd42016-09-10 22:43:48 +02001630 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001631
1632 ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
Christian Heimes2875c602021-04-19 07:27:10 +02001633 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_SERVER)
Christian Heimes4c05b472013-11-23 15:58:30 +01001634 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001635 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001636
Christian Heimes2875c602021-04-19 07:27:10 +02001637
1638
Christian Heimes67986f92013-11-23 22:43:47 +01001639 def test__create_stdlib_context(self):
1640 ctx = ssl._create_stdlib_context()
Christian Heimes2875c602021-04-19 07:27:10 +02001641 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes67986f92013-11-23 22:43:47 +01001642 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001643 self.assertFalse(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001644 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001645
Christian Heimes2875c602021-04-19 07:27:10 +02001646 with warnings_helper.check_warnings():
1647 ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1)
Christian Heimes67986f92013-11-23 22:43:47 +01001648 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
1649 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001650 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001651
Christian Heimes2875c602021-04-19 07:27:10 +02001652 with warnings_helper.check_warnings():
1653 ctx = ssl._create_stdlib_context(
1654 ssl.PROTOCOL_TLSv1_2,
1655 cert_reqs=ssl.CERT_REQUIRED,
1656 check_hostname=True
1657 )
1658 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1_2)
Christian Heimes67986f92013-11-23 22:43:47 +01001659 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimesa02c69a2013-12-02 20:59:28 +01001660 self.assertTrue(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001661 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001662
1663 ctx = ssl._create_stdlib_context(purpose=ssl.Purpose.CLIENT_AUTH)
Christian Heimes2875c602021-04-19 07:27:10 +02001664 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_SERVER)
Christian Heimes67986f92013-11-23 22:43:47 +01001665 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001666 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001667
Christian Heimes1aa9a752013-12-02 02:41:19 +01001668 def test_check_hostname(self):
Christian Heimes2875c602021-04-19 07:27:10 +02001669 with warnings_helper.check_warnings():
1670 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001671 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001672 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001673
Christian Heimese82c0342017-09-15 20:29:57 +02001674 # Auto set CERT_REQUIRED
1675 ctx.check_hostname = True
1676 self.assertTrue(ctx.check_hostname)
1677 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1678 ctx.check_hostname = False
Christian Heimes1aa9a752013-12-02 02:41:19 +01001679 ctx.verify_mode = ssl.CERT_REQUIRED
1680 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001681 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001682
Christian Heimese82c0342017-09-15 20:29:57 +02001683 # Changing verify_mode does not affect check_hostname
1684 ctx.check_hostname = False
1685 ctx.verify_mode = ssl.CERT_NONE
1686 ctx.check_hostname = False
1687 self.assertFalse(ctx.check_hostname)
1688 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1689 # Auto set
Christian Heimes1aa9a752013-12-02 02:41:19 +01001690 ctx.check_hostname = True
1691 self.assertTrue(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001692 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1693
1694 ctx.check_hostname = False
1695 ctx.verify_mode = ssl.CERT_OPTIONAL
1696 ctx.check_hostname = False
1697 self.assertFalse(ctx.check_hostname)
1698 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1699 # keep CERT_OPTIONAL
1700 ctx.check_hostname = True
1701 self.assertTrue(ctx.check_hostname)
1702 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001703
1704 # Cannot set CERT_NONE with check_hostname enabled
1705 with self.assertRaises(ValueError):
1706 ctx.verify_mode = ssl.CERT_NONE
1707 ctx.check_hostname = False
1708 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001709 ctx.verify_mode = ssl.CERT_NONE
1710 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001711
Christian Heimes5fe668c2016-09-12 00:01:11 +02001712 def test_context_client_server(self):
1713 # PROTOCOL_TLS_CLIENT has sane defaults
1714 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1715 self.assertTrue(ctx.check_hostname)
1716 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1717
1718 # PROTOCOL_TLS_SERVER has different but also sane defaults
1719 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1720 self.assertFalse(ctx.check_hostname)
1721 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1722
Christian Heimes4df60f12017-09-15 20:26:05 +02001723 def test_context_custom_class(self):
1724 class MySSLSocket(ssl.SSLSocket):
1725 pass
1726
1727 class MySSLObject(ssl.SSLObject):
1728 pass
1729
1730 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1731 ctx.sslsocket_class = MySSLSocket
1732 ctx.sslobject_class = MySSLObject
1733
1734 with ctx.wrap_socket(socket.socket(), server_side=True) as sock:
1735 self.assertIsInstance(sock, MySSLSocket)
1736 obj = ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO())
1737 self.assertIsInstance(obj, MySSLObject)
1738
Christian Heimes78c7d522019-06-03 21:00:10 +02001739 def test_num_tickest(self):
1740 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1741 self.assertEqual(ctx.num_tickets, 2)
1742 ctx.num_tickets = 1
1743 self.assertEqual(ctx.num_tickets, 1)
1744 ctx.num_tickets = 0
1745 self.assertEqual(ctx.num_tickets, 0)
1746 with self.assertRaises(ValueError):
1747 ctx.num_tickets = -1
1748 with self.assertRaises(TypeError):
1749 ctx.num_tickets = None
1750
1751 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1752 self.assertEqual(ctx.num_tickets, 2)
1753 with self.assertRaises(ValueError):
1754 ctx.num_tickets = 1
1755
Antoine Pitrou152efa22010-05-16 18:19:27 +00001756
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001757class SSLErrorTests(unittest.TestCase):
1758
1759 def test_str(self):
1760 # The str() of a SSLError doesn't include the errno
1761 e = ssl.SSLError(1, "foo")
1762 self.assertEqual(str(e), "foo")
1763 self.assertEqual(e.errno, 1)
1764 # Same for a subclass
1765 e = ssl.SSLZeroReturnError(1, "foo")
1766 self.assertEqual(str(e), "foo")
1767 self.assertEqual(e.errno, 1)
1768
Paul Monsonf3550692019-06-19 13:09:54 -07001769 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001770 def test_lib_reason(self):
1771 # Test the library and reason attributes
Christian Heimesa170fa12017-09-15 20:27:30 +02001772 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001773 with self.assertRaises(ssl.SSLError) as cm:
1774 ctx.load_dh_params(CERTFILE)
1775 self.assertEqual(cm.exception.library, 'PEM')
1776 self.assertEqual(cm.exception.reason, 'NO_START_LINE')
1777 s = str(cm.exception)
1778 self.assertTrue(s.startswith("[PEM: NO_START_LINE] no start line"), s)
1779
1780 def test_subclass(self):
1781 # Check that the appropriate SSLError subclass is raised
1782 # (this only tests one of them)
Christian Heimesa170fa12017-09-15 20:27:30 +02001783 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1784 ctx.check_hostname = False
1785 ctx.verify_mode = ssl.CERT_NONE
Giampaolo Rodolaeb7e29f2019-04-09 00:34:02 +02001786 with socket.create_server(("127.0.0.1", 0)) as s:
1787 c = socket.create_connection(s.getsockname())
Antoine Pitroue1ceb502013-01-12 21:54:44 +01001788 c.setblocking(False)
1789 with ctx.wrap_socket(c, False, do_handshake_on_connect=False) as c:
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001790 with self.assertRaises(ssl.SSLWantReadError) as cm:
1791 c.do_handshake()
1792 s = str(cm.exception)
1793 self.assertTrue(s.startswith("The operation did not complete (read)"), s)
1794 # For compatibility
1795 self.assertEqual(cm.exception.errno, ssl.SSL_ERROR_WANT_READ)
1796
1797
Christian Heimes61d478c2018-01-27 15:51:38 +01001798 def test_bad_server_hostname(self):
1799 ctx = ssl.create_default_context()
1800 with self.assertRaises(ValueError):
1801 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1802 server_hostname="")
1803 with self.assertRaises(ValueError):
1804 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1805 server_hostname=".example.org")
Christian Heimesd02ac252018-03-25 12:36:13 +02001806 with self.assertRaises(TypeError):
1807 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1808 server_hostname="example.org\x00evil.com")
Christian Heimes61d478c2018-01-27 15:51:38 +01001809
1810
Antoine Pitroub1fdf472014-10-05 20:41:53 +02001811class MemoryBIOTests(unittest.TestCase):
1812
1813 def test_read_write(self):
1814 bio = ssl.MemoryBIO()
1815 bio.write(b'foo')
1816 self.assertEqual(bio.read(), b'foo')
1817 self.assertEqual(bio.read(), b'')
1818 bio.write(b'foo')
1819 bio.write(b'bar')
1820 self.assertEqual(bio.read(), b'foobar')
1821 self.assertEqual(bio.read(), b'')
1822 bio.write(b'baz')
1823 self.assertEqual(bio.read(2), b'ba')
1824 self.assertEqual(bio.read(1), b'z')
1825 self.assertEqual(bio.read(1), b'')
1826
1827 def test_eof(self):
1828 bio = ssl.MemoryBIO()
1829 self.assertFalse(bio.eof)
1830 self.assertEqual(bio.read(), b'')
1831 self.assertFalse(bio.eof)
1832 bio.write(b'foo')
1833 self.assertFalse(bio.eof)
1834 bio.write_eof()
1835 self.assertFalse(bio.eof)
1836 self.assertEqual(bio.read(2), b'fo')
1837 self.assertFalse(bio.eof)
1838 self.assertEqual(bio.read(1), b'o')
1839 self.assertTrue(bio.eof)
1840 self.assertEqual(bio.read(), b'')
1841 self.assertTrue(bio.eof)
1842
1843 def test_pending(self):
1844 bio = ssl.MemoryBIO()
1845 self.assertEqual(bio.pending, 0)
1846 bio.write(b'foo')
1847 self.assertEqual(bio.pending, 3)
1848 for i in range(3):
1849 bio.read(1)
1850 self.assertEqual(bio.pending, 3-i-1)
1851 for i in range(3):
1852 bio.write(b'x')
1853 self.assertEqual(bio.pending, i+1)
1854 bio.read()
1855 self.assertEqual(bio.pending, 0)
1856
1857 def test_buffer_types(self):
1858 bio = ssl.MemoryBIO()
1859 bio.write(b'foo')
1860 self.assertEqual(bio.read(), b'foo')
1861 bio.write(bytearray(b'bar'))
1862 self.assertEqual(bio.read(), b'bar')
1863 bio.write(memoryview(b'baz'))
1864 self.assertEqual(bio.read(), b'baz')
1865
1866 def test_error_types(self):
1867 bio = ssl.MemoryBIO()
1868 self.assertRaises(TypeError, bio.write, 'foo')
1869 self.assertRaises(TypeError, bio.write, None)
1870 self.assertRaises(TypeError, bio.write, True)
1871 self.assertRaises(TypeError, bio.write, 1)
1872
1873
Christian Heimes9d50ab52018-02-27 10:17:30 +01001874class SSLObjectTests(unittest.TestCase):
1875 def test_private_init(self):
1876 bio = ssl.MemoryBIO()
1877 with self.assertRaisesRegex(TypeError, "public constructor"):
1878 ssl.SSLObject(bio, bio)
1879
Nathaniel J. Smithc0da5822018-09-21 21:44:12 -07001880 def test_unwrap(self):
1881 client_ctx, server_ctx, hostname = testing_context()
1882 c_in = ssl.MemoryBIO()
1883 c_out = ssl.MemoryBIO()
1884 s_in = ssl.MemoryBIO()
1885 s_out = ssl.MemoryBIO()
1886 client = client_ctx.wrap_bio(c_in, c_out, server_hostname=hostname)
1887 server = server_ctx.wrap_bio(s_in, s_out, server_side=True)
1888
1889 # Loop on the handshake for a bit to get it settled
1890 for _ in range(5):
1891 try:
1892 client.do_handshake()
1893 except ssl.SSLWantReadError:
1894 pass
1895 if c_out.pending:
1896 s_in.write(c_out.read())
1897 try:
1898 server.do_handshake()
1899 except ssl.SSLWantReadError:
1900 pass
1901 if s_out.pending:
1902 c_in.write(s_out.read())
1903 # Now the handshakes should be complete (don't raise WantReadError)
1904 client.do_handshake()
1905 server.do_handshake()
1906
1907 # Now if we unwrap one side unilaterally, it should send close-notify
1908 # and raise WantReadError:
1909 with self.assertRaises(ssl.SSLWantReadError):
1910 client.unwrap()
1911
1912 # But server.unwrap() does not raise, because it reads the client's
1913 # close-notify:
1914 s_in.write(c_out.read())
1915 server.unwrap()
1916
1917 # And now that the client gets the server's close-notify, it doesn't
1918 # raise either.
1919 c_in.write(s_out.read())
1920 client.unwrap()
Christian Heimes9d50ab52018-02-27 10:17:30 +01001921
Martin Panter3840b2a2016-03-27 01:53:46 +00001922class SimpleBackgroundTests(unittest.TestCase):
Martin Panter3840b2a2016-03-27 01:53:46 +00001923 """Tests that connect to a simple server running in the background"""
1924
1925 def setUp(self):
juhovh49fdf112021-04-18 21:11:48 +10001926 self.server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1927 self.server_context.load_cert_chain(SIGNED_CERTFILE)
1928 server = ThreadedEchoServer(context=self.server_context)
Martin Panter3840b2a2016-03-27 01:53:46 +00001929 self.server_addr = (HOST, server.port)
1930 server.__enter__()
1931 self.addCleanup(server.__exit__, None, None, None)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001932
Antoine Pitrou480a1242010-04-28 21:37:09 +00001933 def test_connect(self):
Christian Heimesd0486372016-09-10 23:23:33 +02001934 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001935 cert_reqs=ssl.CERT_NONE) as s:
1936 s.connect(self.server_addr)
1937 self.assertEqual({}, s.getpeercert())
Christian Heimesa5d07652016-09-24 10:48:05 +02001938 self.assertFalse(s.server_side)
Antoine Pitrou350c7222010-09-09 13:31:46 +00001939
Martin Panter3840b2a2016-03-27 01:53:46 +00001940 # this should succeed because we specify the root cert
Christian Heimesd0486372016-09-10 23:23:33 +02001941 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001942 cert_reqs=ssl.CERT_REQUIRED,
1943 ca_certs=SIGNING_CA) as s:
1944 s.connect(self.server_addr)
1945 self.assertTrue(s.getpeercert())
Christian Heimesa5d07652016-09-24 10:48:05 +02001946 self.assertFalse(s.server_side)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001947
Martin Panter3840b2a2016-03-27 01:53:46 +00001948 def test_connect_fail(self):
1949 # This should fail because we have no verification certs. Connection
1950 # failure crashes ThreadedEchoServer, so run this in an independent
1951 # test method.
Christian Heimesd0486372016-09-10 23:23:33 +02001952 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001953 cert_reqs=ssl.CERT_REQUIRED)
1954 self.addCleanup(s.close)
1955 self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
1956 s.connect, self.server_addr)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001957
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00001958 def test_connect_ex(self):
1959 # Issue #11326: check connect_ex() implementation
Christian Heimesd0486372016-09-10 23:23:33 +02001960 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001961 cert_reqs=ssl.CERT_REQUIRED,
1962 ca_certs=SIGNING_CA)
1963 self.addCleanup(s.close)
1964 self.assertEqual(0, s.connect_ex(self.server_addr))
1965 self.assertTrue(s.getpeercert())
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00001966
1967 def test_non_blocking_connect_ex(self):
1968 # Issue #11326: non-blocking connect_ex() should allow handshake
1969 # to proceed after the socket gets ready.
Christian Heimesd0486372016-09-10 23:23:33 +02001970 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001971 cert_reqs=ssl.CERT_REQUIRED,
1972 ca_certs=SIGNING_CA,
1973 do_handshake_on_connect=False)
1974 self.addCleanup(s.close)
1975 s.setblocking(False)
1976 rc = s.connect_ex(self.server_addr)
1977 # EWOULDBLOCK under Windows, EINPROGRESS elsewhere
1978 self.assertIn(rc, (0, errno.EINPROGRESS, errno.EWOULDBLOCK))
1979 # Wait for connect to finish
1980 select.select([], [s], [], 5.0)
1981 # Non-blocking handshake
1982 while True:
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00001983 try:
Martin Panter3840b2a2016-03-27 01:53:46 +00001984 s.do_handshake()
1985 break
1986 except ssl.SSLWantReadError:
1987 select.select([s], [], [], 5.0)
1988 except ssl.SSLWantWriteError:
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00001989 select.select([], [s], [], 5.0)
Martin Panter3840b2a2016-03-27 01:53:46 +00001990 # SSL established
1991 self.assertTrue(s.getpeercert())
Antoine Pitrou40f12ab2012-12-28 19:03:43 +01001992
Antoine Pitrou152efa22010-05-16 18:19:27 +00001993 def test_connect_with_context(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00001994 # Same as test_connect, but with a separately created context
Christian Heimes2875c602021-04-19 07:27:10 +02001995 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1996 ctx.check_hostname = False
1997 ctx.verify_mode = ssl.CERT_NONE
Martin Panter3840b2a2016-03-27 01:53:46 +00001998 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
1999 s.connect(self.server_addr)
2000 self.assertEqual({}, s.getpeercert())
2001 # Same with a server hostname
2002 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2003 server_hostname="dummy") as s:
2004 s.connect(self.server_addr)
2005 ctx.verify_mode = ssl.CERT_REQUIRED
2006 # This should succeed because we specify the root cert
2007 ctx.load_verify_locations(SIGNING_CA)
2008 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2009 s.connect(self.server_addr)
2010 cert = s.getpeercert()
2011 self.assertTrue(cert)
2012
2013 def test_connect_with_context_fail(self):
2014 # This should fail because we have no verification certs. Connection
2015 # failure crashes ThreadedEchoServer, so run this in an independent
2016 # test method.
Christian Heimes2875c602021-04-19 07:27:10 +02002017 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2018 s = ctx.wrap_socket(
2019 socket.socket(socket.AF_INET),
2020 server_hostname=SIGNED_CERTFILE_HOSTNAME
2021 )
Martin Panter3840b2a2016-03-27 01:53:46 +00002022 self.addCleanup(s.close)
2023 self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
2024 s.connect, self.server_addr)
Antoine Pitrou152efa22010-05-16 18:19:27 +00002025
2026 def test_connect_capath(self):
2027 # Verify server certificates using the `capath` argument
Antoine Pitrou467f28d2010-05-16 19:22:44 +00002028 # NOTE: the subject hashing algorithm has been changed between
2029 # OpenSSL 0.9.8n and 1.0.0, as a result the capath directory must
2030 # contain both versions of each certificate (same content, different
Antoine Pitroud7e4c1c2010-05-17 14:13:10 +00002031 # filename) for this test to be portable across OpenSSL releases.
Christian Heimes2875c602021-04-19 07:27:10 +02002032 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002033 ctx.load_verify_locations(capath=CAPATH)
Christian Heimes2875c602021-04-19 07:27:10 +02002034 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2035 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002036 s.connect(self.server_addr)
2037 cert = s.getpeercert()
2038 self.assertTrue(cert)
Christian Heimes529525f2018-05-23 22:24:45 +02002039
Martin Panter3840b2a2016-03-27 01:53:46 +00002040 # Same with a bytes `capath` argument
Christian Heimes2875c602021-04-19 07:27:10 +02002041 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002042 ctx.load_verify_locations(capath=BYTES_CAPATH)
Christian Heimes2875c602021-04-19 07:27:10 +02002043 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2044 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002045 s.connect(self.server_addr)
2046 cert = s.getpeercert()
2047 self.assertTrue(cert)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002048
Christian Heimesefff7062013-11-21 03:35:02 +01002049 def test_connect_cadata(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002050 with open(SIGNING_CA) as f:
Christian Heimesefff7062013-11-21 03:35:02 +01002051 pem = f.read()
2052 der = ssl.PEM_cert_to_DER_cert(pem)
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(cadata=pem)
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 Heimesefff7062013-11-21 03:35:02 +01002060
Martin Panter3840b2a2016-03-27 01:53:46 +00002061 # same with DER
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(cadata=der)
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)
Christian Heimesefff7062013-11-21 03:35:02 +01002069
Antoine Pitroue3220242010-04-24 11:13:53 +00002070 @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
2071 def test_makefile_close(self):
2072 # Issue #5238: creating a file-like object with makefile() shouldn't
2073 # delay closing the underlying "real socket" (here tested with its
2074 # file descriptor, hence skipping the test under Windows).
Christian Heimesd0486372016-09-10 23:23:33 +02002075 ss = test_wrap_socket(socket.socket(socket.AF_INET))
Martin Panter3840b2a2016-03-27 01:53:46 +00002076 ss.connect(self.server_addr)
2077 fd = ss.fileno()
2078 f = ss.makefile()
2079 f.close()
2080 # The fd is still open
2081 os.read(fd, 0)
2082 # Closing the SSL socket should close the fd too
2083 ss.close()
2084 gc.collect()
2085 with self.assertRaises(OSError) as e:
Antoine Pitroue3220242010-04-24 11:13:53 +00002086 os.read(fd, 0)
Martin Panter3840b2a2016-03-27 01:53:46 +00002087 self.assertEqual(e.exception.errno, errno.EBADF)
Antoine Pitroue3220242010-04-24 11:13:53 +00002088
Antoine Pitrou480a1242010-04-28 21:37:09 +00002089 def test_non_blocking_handshake(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002090 s = socket.socket(socket.AF_INET)
2091 s.connect(self.server_addr)
2092 s.setblocking(False)
Christian Heimesd0486372016-09-10 23:23:33 +02002093 s = test_wrap_socket(s,
Martin Panter3840b2a2016-03-27 01:53:46 +00002094 cert_reqs=ssl.CERT_NONE,
2095 do_handshake_on_connect=False)
2096 self.addCleanup(s.close)
2097 count = 0
2098 while True:
2099 try:
2100 count += 1
2101 s.do_handshake()
2102 break
2103 except ssl.SSLWantReadError:
2104 select.select([s], [], [])
2105 except ssl.SSLWantWriteError:
2106 select.select([], [s], [])
2107 if support.verbose:
2108 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002109
Antoine Pitrou480a1242010-04-28 21:37:09 +00002110 def test_get_server_certificate(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002111 _test_get_server_certificate(self, *self.server_addr, cert=SIGNING_CA)
Antoine Pitrou5aefa662011-04-28 19:24:46 +02002112
juhovh49fdf112021-04-18 21:11:48 +10002113 def test_get_server_certificate_sni(self):
2114 host, port = self.server_addr
2115 server_names = []
2116
2117 # We store servername_cb arguments to make sure they match the host
2118 def servername_cb(ssl_sock, server_name, initial_context):
2119 server_names.append(server_name)
2120 self.server_context.set_servername_callback(servername_cb)
2121
2122 pem = ssl.get_server_certificate((host, port))
2123 if not pem:
2124 self.fail("No server certificate on %s:%s!" % (host, port))
2125
2126 pem = ssl.get_server_certificate((host, port), ca_certs=SIGNING_CA)
2127 if not pem:
2128 self.fail("No server certificate on %s:%s!" % (host, port))
2129 if support.verbose:
2130 sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port, pem))
2131
2132 self.assertEqual(server_names, [host, host])
2133
Martin Panter3840b2a2016-03-27 01:53:46 +00002134 def test_get_server_certificate_fail(self):
2135 # Connection failure crashes ThreadedEchoServer, so run this in an
2136 # independent test method
2137 _test_get_server_certificate_fail(self, *self.server_addr)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002138
Zackery Spytzb2fac1a2021-04-23 22:46:01 -06002139 def test_get_server_certificate_timeout(self):
Christian Heimesf05c2ae2021-04-24 07:54:08 +02002140 def servername_cb(ssl_sock, server_name, initial_context):
2141 time.sleep(0.2)
2142 self.server_context.set_servername_callback(servername_cb)
2143
Zackery Spytzb2fac1a2021-04-23 22:46:01 -06002144 with self.assertRaises(socket.timeout):
2145 ssl.get_server_certificate(self.server_addr, ca_certs=SIGNING_CA,
Christian Heimesf05c2ae2021-04-24 07:54:08 +02002146 timeout=0.1)
Zackery Spytzb2fac1a2021-04-23 22:46:01 -06002147
Antoine Pitrouf4c7bad2010-08-15 23:02:22 +00002148 def test_ciphers(self):
Christian Heimesd0486372016-09-10 23:23:33 +02002149 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002150 cert_reqs=ssl.CERT_NONE, ciphers="ALL") as s:
2151 s.connect(self.server_addr)
Christian Heimesd0486372016-09-10 23:23:33 +02002152 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002153 cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT") as s:
2154 s.connect(self.server_addr)
2155 # Error checking can happen at instantiation or when connecting
2156 with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
2157 with socket.socket(socket.AF_INET) as sock:
Christian Heimesd0486372016-09-10 23:23:33 +02002158 s = test_wrap_socket(sock,
Martin Panter3840b2a2016-03-27 01:53:46 +00002159 cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
2160 s.connect(self.server_addr)
Antoine Pitroufec12ff2010-04-21 19:46:23 +00002161
Christian Heimes9a5395a2013-06-17 15:44:12 +02002162 def test_get_ca_certs_capath(self):
2163 # capath certs are loaded on request
Christian Heimesa170fa12017-09-15 20:27:30 +02002164 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002165 ctx.load_verify_locations(capath=CAPATH)
2166 self.assertEqual(ctx.get_ca_certs(), [])
Christian Heimesa170fa12017-09-15 20:27:30 +02002167 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2168 server_hostname='localhost') as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002169 s.connect(self.server_addr)
2170 cert = s.getpeercert()
2171 self.assertTrue(cert)
2172 self.assertEqual(len(ctx.get_ca_certs()), 1)
Christian Heimes9a5395a2013-06-17 15:44:12 +02002173
Christian Heimes8e7f3942013-12-05 07:41:08 +01002174 def test_context_setget(self):
2175 # Check that the context of a connected socket can be replaced.
Christian Heimesa170fa12017-09-15 20:27:30 +02002176 ctx1 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2177 ctx1.load_verify_locations(capath=CAPATH)
2178 ctx2 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2179 ctx2.load_verify_locations(capath=CAPATH)
Martin Panter3840b2a2016-03-27 01:53:46 +00002180 s = socket.socket(socket.AF_INET)
Christian Heimesa170fa12017-09-15 20:27:30 +02002181 with ctx1.wrap_socket(s, server_hostname='localhost') as ss:
Martin Panter3840b2a2016-03-27 01:53:46 +00002182 ss.connect(self.server_addr)
2183 self.assertIs(ss.context, ctx1)
2184 self.assertIs(ss._sslobj.context, ctx1)
2185 ss.context = ctx2
2186 self.assertIs(ss.context, ctx2)
2187 self.assertIs(ss._sslobj.context, ctx2)
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002188
2189 def ssl_io_loop(self, sock, incoming, outgoing, func, *args, **kwargs):
2190 # A simple IO loop. Call func(*args) depending on the error we get
2191 # (WANT_READ or WANT_WRITE) move data between the socket and the BIOs.
Victor Stinner0d63bac2019-12-11 11:30:03 +01002192 timeout = kwargs.get('timeout', support.SHORT_TIMEOUT)
Victor Stinner50a72af2017-09-11 09:34:24 -07002193 deadline = time.monotonic() + timeout
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002194 count = 0
2195 while True:
Victor Stinner50a72af2017-09-11 09:34:24 -07002196 if time.monotonic() > deadline:
2197 self.fail("timeout")
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002198 errno = None
2199 count += 1
2200 try:
2201 ret = func(*args)
2202 except ssl.SSLError as e:
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002203 if e.errno not in (ssl.SSL_ERROR_WANT_READ,
Martin Panter40b97ec2016-01-14 13:05:46 +00002204 ssl.SSL_ERROR_WANT_WRITE):
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002205 raise
2206 errno = e.errno
2207 # Get any data from the outgoing BIO irrespective of any error, and
2208 # send it to the socket.
2209 buf = outgoing.read()
2210 sock.sendall(buf)
2211 # If there's no error, we're done. For WANT_READ, we need to get
2212 # data from the socket and put it in the incoming BIO.
2213 if errno is None:
2214 break
2215 elif errno == ssl.SSL_ERROR_WANT_READ:
2216 buf = sock.recv(32768)
2217 if buf:
2218 incoming.write(buf)
2219 else:
2220 incoming.write_eof()
2221 if support.verbose:
2222 sys.stdout.write("Needed %d calls to complete %s().\n"
2223 % (count, func.__name__))
2224 return ret
2225
Martin Panter3840b2a2016-03-27 01:53:46 +00002226 def test_bio_handshake(self):
2227 sock = socket.socket(socket.AF_INET)
2228 self.addCleanup(sock.close)
2229 sock.connect(self.server_addr)
2230 incoming = ssl.MemoryBIO()
2231 outgoing = ssl.MemoryBIO()
Christian Heimesa170fa12017-09-15 20:27:30 +02002232 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2233 self.assertTrue(ctx.check_hostname)
2234 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Martin Panter3840b2a2016-03-27 01:53:46 +00002235 ctx.load_verify_locations(SIGNING_CA)
Christian Heimesa170fa12017-09-15 20:27:30 +02002236 sslobj = ctx.wrap_bio(incoming, outgoing, False,
2237 SIGNED_CERTFILE_HOSTNAME)
Martin Panter3840b2a2016-03-27 01:53:46 +00002238 self.assertIs(sslobj._sslobj.owner, sslobj)
2239 self.assertIsNone(sslobj.cipher())
Christian Heimes68771112017-09-05 21:55:40 -07002240 self.assertIsNone(sslobj.version())
Christian Heimes01113fa2016-09-05 23:23:24 +02002241 self.assertIsNotNone(sslobj.shared_ciphers())
Martin Panter3840b2a2016-03-27 01:53:46 +00002242 self.assertRaises(ValueError, sslobj.getpeercert)
2243 if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
2244 self.assertIsNone(sslobj.get_channel_binding('tls-unique'))
2245 self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
2246 self.assertTrue(sslobj.cipher())
Christian Heimes01113fa2016-09-05 23:23:24 +02002247 self.assertIsNotNone(sslobj.shared_ciphers())
Christian Heimes68771112017-09-05 21:55:40 -07002248 self.assertIsNotNone(sslobj.version())
Martin Panter3840b2a2016-03-27 01:53:46 +00002249 self.assertTrue(sslobj.getpeercert())
2250 if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
2251 self.assertTrue(sslobj.get_channel_binding('tls-unique'))
2252 try:
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002253 self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
Martin Panter3840b2a2016-03-27 01:53:46 +00002254 except ssl.SSLSyscallError:
2255 # If the server shuts down the TCP connection without sending a
2256 # secure shutdown message, this is reported as SSL_ERROR_SYSCALL
2257 pass
2258 self.assertRaises(ssl.SSLError, sslobj.write, b'foo')
2259
2260 def test_bio_read_write_data(self):
2261 sock = socket.socket(socket.AF_INET)
2262 self.addCleanup(sock.close)
2263 sock.connect(self.server_addr)
2264 incoming = ssl.MemoryBIO()
2265 outgoing = ssl.MemoryBIO()
Christian Heimes2875c602021-04-19 07:27:10 +02002266 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2267 ctx.check_hostname = False
Martin Panter3840b2a2016-03-27 01:53:46 +00002268 ctx.verify_mode = ssl.CERT_NONE
2269 sslobj = ctx.wrap_bio(incoming, outgoing, False)
2270 self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
2271 req = b'FOO\n'
2272 self.ssl_io_loop(sock, incoming, outgoing, sslobj.write, req)
2273 buf = self.ssl_io_loop(sock, incoming, outgoing, sslobj.read, 1024)
2274 self.assertEqual(buf, b'foo\n')
2275 self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002276
2277
Martin Panter3840b2a2016-03-27 01:53:46 +00002278class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002279
Martin Panter3840b2a2016-03-27 01:53:46 +00002280 def test_timeout_connect_ex(self):
2281 # Issue #12065: on a timeout, connect_ex() should return the original
2282 # errno (mimicking the behaviour of non-SSL sockets).
Serhiy Storchakabfb1cf42020-04-29 10:36:20 +03002283 with socket_helper.transient_internet(REMOTE_HOST):
Christian Heimesd0486372016-09-10 23:23:33 +02002284 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002285 cert_reqs=ssl.CERT_REQUIRED,
2286 do_handshake_on_connect=False)
2287 self.addCleanup(s.close)
2288 s.settimeout(0.0000001)
2289 rc = s.connect_ex((REMOTE_HOST, 443))
2290 if rc == 0:
2291 self.skipTest("REMOTE_HOST responded too quickly")
Carl Meyer29c451c2021-03-27 15:52:28 -06002292 elif rc == errno.ENETUNREACH:
2293 self.skipTest("Network unreachable.")
Martin Panter3840b2a2016-03-27 01:53:46 +00002294 self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK))
2295
Serhiy Storchaka16994912020-04-25 10:06:29 +03002296 @unittest.skipUnless(socket_helper.IPV6_ENABLED, 'Needs IPv6')
Martin Panter3840b2a2016-03-27 01:53:46 +00002297 def test_get_server_certificate_ipv6(self):
Serhiy Storchakabfb1cf42020-04-29 10:36:20 +03002298 with socket_helper.transient_internet('ipv6.google.com'):
Martin Panter3840b2a2016-03-27 01:53:46 +00002299 _test_get_server_certificate(self, 'ipv6.google.com', 443)
2300 _test_get_server_certificate_fail(self, 'ipv6.google.com', 443)
2301
Martin Panter3840b2a2016-03-27 01:53:46 +00002302
2303def _test_get_server_certificate(test, host, port, cert=None):
2304 pem = ssl.get_server_certificate((host, port))
2305 if not pem:
2306 test.fail("No server certificate on %s:%s!" % (host, port))
2307
2308 pem = ssl.get_server_certificate((host, port), ca_certs=cert)
2309 if not pem:
2310 test.fail("No server certificate on %s:%s!" % (host, port))
2311 if support.verbose:
2312 sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem))
2313
2314def _test_get_server_certificate_fail(test, host, port):
2315 try:
2316 pem = ssl.get_server_certificate((host, port), ca_certs=CERTFILE)
2317 except ssl.SSLError as x:
2318 #should fail
2319 if support.verbose:
2320 sys.stdout.write("%s\n" % x)
2321 else:
2322 test.fail("Got server certificate %s for %s:%s!" % (pem, host, port))
2323
2324
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002325from test.ssl_servers import make_https_server
Antoine Pitrou803e6d62010-10-13 10:36:15 +00002326
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002327class ThreadedEchoServer(threading.Thread):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002328
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002329 class ConnectionHandler(threading.Thread):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002330
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002331 """A mildly complicated class, because we want it to work both
2332 with and without the SSL wrapper around the socket connection, so
2333 that we can test the STARTTLS functionality."""
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002334
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002335 def __init__(self, server, connsock, addr):
2336 self.server = server
2337 self.running = False
2338 self.sock = connsock
2339 self.addr = addr
Serhiy Storchaka5eca7f32019-09-01 12:12:52 +03002340 self.sock.setblocking(True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002341 self.sslconn = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002342 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +00002343 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002344
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002345 def wrap_conn(self):
2346 try:
2347 self.sslconn = self.server.context.wrap_socket(
2348 self.sock, server_side=True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002349 self.server.selected_alpn_protocols.append(self.sslconn.selected_alpn_protocol())
Paul Monsonfb7e7502019-05-15 15:38:55 -07002350 except (ConnectionResetError, BrokenPipeError, ConnectionAbortedError) as e:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002351 # We treat ConnectionResetError as though it were an
2352 # SSLError - OpenSSL on Ubuntu abruptly closes the
2353 # connection when asked to use an unsupported protocol.
2354 #
Christian Heimes529525f2018-05-23 22:24:45 +02002355 # BrokenPipeError is raised in TLS 1.3 mode, when OpenSSL
2356 # tries to send session tickets after handshake.
2357 # https://github.com/openssl/openssl/issues/6342
Paul Monsonfb7e7502019-05-15 15:38:55 -07002358 #
2359 # ConnectionAbortedError is raised in TLS 1.3 mode, when OpenSSL
2360 # tries to send session tickets after handshake when using WinSock.
Christian Heimes529525f2018-05-23 22:24:45 +02002361 self.server.conn_errors.append(str(e))
2362 if self.server.chatty:
2363 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
2364 self.running = False
2365 self.close()
2366 return False
2367 except (ssl.SSLError, OSError) as e:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002368 # OSError may occur with wrong protocols, e.g. both
2369 # sides use PROTOCOL_TLS_SERVER.
2370 #
2371 # XXX Various errors can have happened here, for example
2372 # a mismatching protocol version, an invalid certificate,
2373 # or a low-level bug. This should be made more discriminating.
2374 #
2375 # bpo-31323: Store the exception as string to prevent
2376 # a reference leak: server -> conn_errors -> exception
2377 # -> traceback -> self (ConnectionHandler) -> server
2378 self.server.conn_errors.append(str(e))
2379 if self.server.chatty:
2380 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
2381 self.running = False
2382 self.server.stop()
2383 self.close()
2384 return False
2385 else:
2386 self.server.shared_ciphers.append(self.sslconn.shared_ciphers())
2387 if self.server.context.verify_mode == ssl.CERT_REQUIRED:
2388 cert = self.sslconn.getpeercert()
2389 if support.verbose and self.server.chatty:
2390 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
2391 cert_binary = self.sslconn.getpeercert(True)
2392 if support.verbose and self.server.chatty:
2393 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
2394 cipher = self.sslconn.cipher()
2395 if support.verbose and self.server.chatty:
2396 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002397 return True
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002398
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002399 def read(self):
2400 if self.sslconn:
2401 return self.sslconn.read()
2402 else:
2403 return self.sock.recv(1024)
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002404
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002405 def write(self, bytes):
2406 if self.sslconn:
2407 return self.sslconn.write(bytes)
2408 else:
2409 return self.sock.send(bytes)
2410
2411 def close(self):
2412 if self.sslconn:
2413 self.sslconn.close()
2414 else:
2415 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002416
Antoine Pitrou480a1242010-04-28 21:37:09 +00002417 def run(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002418 self.running = True
2419 if not self.server.starttls_server:
2420 if not self.wrap_conn():
2421 return
2422 while self.running:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002423 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002424 msg = self.read()
2425 stripped = msg.strip()
2426 if not stripped:
2427 # eof, so quit this handler
2428 self.running = False
2429 try:
2430 self.sock = self.sslconn.unwrap()
2431 except OSError:
2432 # Many tests shut the TCP connection down
2433 # without an SSL shutdown. This causes
2434 # unwrap() to raise OSError with errno=0!
2435 pass
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00002436 else:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002437 self.sslconn = None
2438 self.close()
2439 elif stripped == b'over':
2440 if support.verbose and self.server.connectionchatty:
2441 sys.stdout.write(" server: client closed connection\n")
2442 self.close()
2443 return
2444 elif (self.server.starttls_server and
2445 stripped == b'STARTTLS'):
2446 if support.verbose and self.server.connectionchatty:
2447 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
2448 self.write(b"OK\n")
2449 if not self.wrap_conn():
2450 return
2451 elif (self.server.starttls_server and self.sslconn
2452 and stripped == b'ENDTLS'):
2453 if support.verbose and self.server.connectionchatty:
2454 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
2455 self.write(b"OK\n")
2456 self.sock = self.sslconn.unwrap()
2457 self.sslconn = None
2458 if support.verbose and self.server.connectionchatty:
2459 sys.stdout.write(" server: connection is now unencrypted...\n")
2460 elif stripped == b'CB tls-unique':
2461 if support.verbose and self.server.connectionchatty:
2462 sys.stdout.write(" server: read CB tls-unique from client, sending our CB data...\n")
2463 data = self.sslconn.get_channel_binding("tls-unique")
2464 self.write(repr(data).encode("us-ascii") + b"\n")
Christian Heimes9fb051f2018-09-23 08:32:31 +02002465 elif stripped == b'PHA':
2466 if support.verbose and self.server.connectionchatty:
2467 sys.stdout.write(" server: initiating post handshake auth\n")
2468 try:
2469 self.sslconn.verify_client_post_handshake()
2470 except ssl.SSLError as e:
2471 self.write(repr(e).encode("us-ascii") + b"\n")
2472 else:
2473 self.write(b"OK\n")
2474 elif stripped == b'HASCERT':
2475 if self.sslconn.getpeercert() is not None:
2476 self.write(b'TRUE\n')
2477 else:
2478 self.write(b'FALSE\n')
2479 elif stripped == b'GETCERT':
2480 cert = self.sslconn.getpeercert()
2481 self.write(repr(cert).encode("us-ascii") + b"\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002482 else:
2483 if (support.verbose and
2484 self.server.connectionchatty):
2485 ctype = (self.sslconn and "encrypted") or "unencrypted"
2486 sys.stdout.write(" server: read %r (%s), sending back %r (%s)...\n"
2487 % (msg, ctype, msg.lower(), ctype))
2488 self.write(msg.lower())
Paul Monsonfb7e7502019-05-15 15:38:55 -07002489 except (ConnectionResetError, ConnectionAbortedError):
Christian Heimes529525f2018-05-23 22:24:45 +02002490 # XXX: OpenSSL 1.1.1 sometimes raises ConnectionResetError
2491 # when connection is not shut down gracefully.
2492 if self.server.chatty and support.verbose:
2493 sys.stdout.write(
2494 " Connection reset by peer: {}\n".format(
2495 self.addr)
2496 )
2497 self.close()
2498 self.running = False
Paul Monsonfb7e7502019-05-15 15:38:55 -07002499 except ssl.SSLError as err:
2500 # On Windows sometimes test_pha_required_nocert receives the
2501 # PEER_DID_NOT_RETURN_A_CERTIFICATE exception
2502 # before the 'tlsv13 alert certificate required' exception.
2503 # If the server is stopped when PEER_DID_NOT_RETURN_A_CERTIFICATE
2504 # is received test_pha_required_nocert fails with ConnectionResetError
2505 # because the underlying socket is closed
2506 if 'PEER_DID_NOT_RETURN_A_CERTIFICATE' == err.reason:
2507 if self.server.chatty and support.verbose:
2508 sys.stdout.write(err.args[1])
2509 # test_pha_required_nocert is expecting this exception
2510 raise ssl.SSLError('tlsv13 alert certificate required')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002511 except OSError:
2512 if self.server.chatty:
2513 handle_error("Test server failure:\n")
Bill Janssen2f5799b2008-06-29 00:08:12 +00002514 self.close()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002515 self.running = False
Christian Heimes529525f2018-05-23 22:24:45 +02002516
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002517 # normally, we'd just stop here, but for the test
2518 # harness, we want to stop the server
2519 self.server.stop()
Bill Janssen54cc54c2007-12-14 22:08:56 +00002520
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002521 def __init__(self, certificate=None, ssl_version=None,
2522 certreqs=None, cacerts=None,
2523 chatty=True, connectionchatty=False, starttls_server=False,
Christian Heimes2875c602021-04-19 07:27:10 +02002524 alpn_protocols=None,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002525 ciphers=None, context=None):
2526 if context:
2527 self.context = context
2528 else:
2529 self.context = ssl.SSLContext(ssl_version
2530 if ssl_version is not None
Christian Heimesa170fa12017-09-15 20:27:30 +02002531 else ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002532 self.context.verify_mode = (certreqs if certreqs is not None
2533 else ssl.CERT_NONE)
2534 if cacerts:
2535 self.context.load_verify_locations(cacerts)
2536 if certificate:
2537 self.context.load_cert_chain(certificate)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002538 if alpn_protocols:
2539 self.context.set_alpn_protocols(alpn_protocols)
2540 if ciphers:
2541 self.context.set_ciphers(ciphers)
2542 self.chatty = chatty
2543 self.connectionchatty = connectionchatty
2544 self.starttls_server = starttls_server
2545 self.sock = socket.socket()
Serhiy Storchaka16994912020-04-25 10:06:29 +03002546 self.port = socket_helper.bind_port(self.sock)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002547 self.flag = None
2548 self.active = False
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002549 self.selected_alpn_protocols = []
2550 self.shared_ciphers = []
2551 self.conn_errors = []
2552 threading.Thread.__init__(self)
2553 self.daemon = True
2554
2555 def __enter__(self):
2556 self.start(threading.Event())
2557 self.flag.wait()
2558 return self
2559
2560 def __exit__(self, *args):
2561 self.stop()
2562 self.join()
2563
2564 def start(self, flag=None):
2565 self.flag = flag
2566 threading.Thread.start(self)
2567
2568 def run(self):
2569 self.sock.settimeout(0.05)
2570 self.sock.listen()
2571 self.active = True
2572 if self.flag:
2573 # signal an event
2574 self.flag.set()
2575 while self.active:
2576 try:
2577 newconn, connaddr = self.sock.accept()
2578 if support.verbose and self.chatty:
2579 sys.stdout.write(' server: new connection from '
2580 + repr(connaddr) + '\n')
2581 handler = self.ConnectionHandler(self, newconn, connaddr)
2582 handler.start()
2583 handler.join()
Christian Heimes03c8ddd2020-11-20 09:26:07 +01002584 except TimeoutError:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002585 pass
2586 except KeyboardInterrupt:
2587 self.stop()
Christian Heimes529525f2018-05-23 22:24:45 +02002588 except BaseException as e:
2589 if support.verbose and self.chatty:
2590 sys.stdout.write(
2591 ' connection handling failed: ' + repr(e) + '\n')
2592
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002593 self.sock.close()
2594
2595 def stop(self):
2596 self.active = False
2597
2598class AsyncoreEchoServer(threading.Thread):
2599
2600 # this one's based on asyncore.dispatcher
2601
2602 class EchoServer (asyncore.dispatcher):
2603
2604 class ConnectionHandler(asyncore.dispatcher_with_send):
2605
2606 def __init__(self, conn, certfile):
2607 self.socket = test_wrap_socket(conn, server_side=True,
2608 certfile=certfile,
2609 do_handshake_on_connect=False)
2610 asyncore.dispatcher_with_send.__init__(self, self.socket)
2611 self._ssl_accepting = True
2612 self._do_ssl_handshake()
2613
2614 def readable(self):
2615 if isinstance(self.socket, ssl.SSLSocket):
2616 while self.socket.pending() > 0:
2617 self.handle_read_event()
2618 return True
2619
2620 def _do_ssl_handshake(self):
2621 try:
2622 self.socket.do_handshake()
2623 except (ssl.SSLWantReadError, ssl.SSLWantWriteError):
2624 return
2625 except ssl.SSLEOFError:
2626 return self.handle_close()
2627 except ssl.SSLError:
Bill Janssen54cc54c2007-12-14 22:08:56 +00002628 raise
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002629 except OSError as err:
2630 if err.args[0] == errno.ECONNABORTED:
2631 return self.handle_close()
2632 else:
2633 self._ssl_accepting = False
Bill Janssen54cc54c2007-12-14 22:08:56 +00002634
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002635 def handle_read(self):
2636 if self._ssl_accepting:
2637 self._do_ssl_handshake()
2638 else:
2639 data = self.recv(1024)
2640 if support.verbose:
2641 sys.stdout.write(" server: read %s from client\n" % repr(data))
2642 if not data:
2643 self.close()
2644 else:
2645 self.send(data.lower())
Bill Janssen54cc54c2007-12-14 22:08:56 +00002646
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002647 def handle_close(self):
2648 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002649 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002650 sys.stdout.write(" server: closed connection %s\n" % self.socket)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002651
2652 def handle_error(self):
2653 raise
2654
Trent Nelson78520002008-04-10 20:54:35 +00002655 def __init__(self, certfile):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002656 self.certfile = certfile
2657 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Serhiy Storchaka16994912020-04-25 10:06:29 +03002658 self.port = socket_helper.bind_port(sock, '')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002659 asyncore.dispatcher.__init__(self, sock)
2660 self.listen(5)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002661
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002662 def handle_accepted(self, sock_obj, addr):
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002663 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002664 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
2665 self.ConnectionHandler(sock_obj, self.certfile)
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002666
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002667 def handle_error(self):
2668 raise
Bill Janssen54cc54c2007-12-14 22:08:56 +00002669
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002670 def __init__(self, certfile):
2671 self.flag = None
2672 self.active = False
2673 self.server = self.EchoServer(certfile)
2674 self.port = self.server.port
2675 threading.Thread.__init__(self)
2676 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +00002677
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002678 def __str__(self):
2679 return "<%s %s>" % (self.__class__.__name__, self.server)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002680
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002681 def __enter__(self):
2682 self.start(threading.Event())
2683 self.flag.wait()
2684 return self
Thomas Woutersed03b412007-08-28 21:37:11 +00002685
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002686 def __exit__(self, *args):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002687 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002688 sys.stdout.write(" cleanup: stopping server.\n")
2689 self.stop()
2690 if support.verbose:
2691 sys.stdout.write(" cleanup: joining server thread.\n")
2692 self.join()
2693 if support.verbose:
2694 sys.stdout.write(" cleanup: successfully joined.\n")
2695 # make sure that ConnectionHandler is removed from socket_map
2696 asyncore.close_all(ignore_all=True)
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01002697
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002698 def start (self, flag=None):
2699 self.flag = flag
2700 threading.Thread.start(self)
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01002701
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002702 def run(self):
2703 self.active = True
2704 if self.flag:
2705 self.flag.set()
2706 while self.active:
Antoine Pitrou773b5db2010-04-27 08:53:36 +00002707 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002708 asyncore.loop(1)
2709 except:
2710 pass
Trent Nelson6b240cd2008-04-10 20:12:06 +00002711
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002712 def stop(self):
2713 self.active = False
2714 self.server.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002715
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002716def server_params_test(client_context, server_context, indata=b"FOO\n",
2717 chatty=True, connectionchatty=False, sni_name=None,
2718 session=None):
2719 """
2720 Launch a server, connect a client to it and try various reads
2721 and writes.
2722 """
2723 stats = {}
2724 server = ThreadedEchoServer(context=server_context,
2725 chatty=chatty,
2726 connectionchatty=False)
2727 with server:
2728 with client_context.wrap_socket(socket.socket(),
2729 server_hostname=sni_name, session=session) as s:
2730 s.connect((HOST, server.port))
2731 for arg in [indata, bytearray(indata), memoryview(indata)]:
2732 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002733 if support.verbose:
Antoine Pitrou18c913e2010-04-27 10:59:39 +00002734 sys.stdout.write(
Antoine Pitrou480a1242010-04-28 21:37:09 +00002735 " client: sending %r...\n" % indata)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002736 s.write(arg)
Antoine Pitrou18c913e2010-04-27 10:59:39 +00002737 outdata = s.read()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002738 if connectionchatty:
2739 if support.verbose:
2740 sys.stdout.write(" client: read %r\n" % outdata)
Trent Nelson6b240cd2008-04-10 20:12:06 +00002741 if outdata != indata.lower():
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002742 raise AssertionError(
Antoine Pitrou480a1242010-04-28 21:37:09 +00002743 "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
2744 % (outdata[:20], len(outdata),
2745 indata[:20].lower(), len(indata)))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002746 s.write(b"over\n")
2747 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002748 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00002749 sys.stdout.write(" client: closing connection.\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002750 stats.update({
2751 'compression': s.compression(),
2752 'cipher': s.cipher(),
2753 'peercert': s.getpeercert(),
2754 'client_alpn_protocol': s.selected_alpn_protocol(),
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002755 'version': s.version(),
2756 'session_reused': s.session_reused,
2757 'session': s.session,
2758 })
2759 s.close()
2760 stats['server_alpn_protocols'] = server.selected_alpn_protocols
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002761 stats['server_shared_ciphers'] = server.shared_ciphers
2762 return stats
Trent Nelson6b240cd2008-04-10 20:12:06 +00002763
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002764def try_protocol_combo(server_protocol, client_protocol, expect_success,
2765 certsreqs=None, server_options=0, client_options=0):
2766 """
2767 Try to SSL-connect using *client_protocol* to *server_protocol*.
2768 If *expect_success* is true, assert that the connection succeeds,
2769 if it's false, assert that the connection fails.
2770 Also, if *expect_success* is a string, assert that it is the protocol
2771 version actually used by the connection.
2772 """
2773 if certsreqs is None:
2774 certsreqs = ssl.CERT_NONE
2775 certtype = {
2776 ssl.CERT_NONE: "CERT_NONE",
2777 ssl.CERT_OPTIONAL: "CERT_OPTIONAL",
2778 ssl.CERT_REQUIRED: "CERT_REQUIRED",
2779 }[certsreqs]
2780 if support.verbose:
2781 formatstr = (expect_success and " %s->%s %s\n") or " {%s->%s} %s\n"
2782 sys.stdout.write(formatstr %
2783 (ssl.get_protocol_name(client_protocol),
2784 ssl.get_protocol_name(server_protocol),
2785 certtype))
Christian Heimes2875c602021-04-19 07:27:10 +02002786
2787 with warnings_helper.check_warnings():
2788 # ignore Deprecation warnings
2789 client_context = ssl.SSLContext(client_protocol)
2790 client_context.options |= client_options
2791 server_context = ssl.SSLContext(server_protocol)
2792 server_context.options |= server_options
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002793
Victor Stinner3ef63442019-02-19 18:06:03 +01002794 min_version = PROTOCOL_TO_TLS_VERSION.get(client_protocol, None)
2795 if (min_version is not None
Christian Heimes2875c602021-04-19 07:27:10 +02002796 # SSLContext.minimum_version is only available on recent OpenSSL
2797 # (setter added in OpenSSL 1.1.0, getter added in OpenSSL 1.1.1)
2798 and hasattr(server_context, 'minimum_version')
2799 and server_protocol == ssl.PROTOCOL_TLS
2800 and server_context.minimum_version > min_version
2801 ):
Victor Stinner3ef63442019-02-19 18:06:03 +01002802 # If OpenSSL configuration is strict and requires more recent TLS
2803 # version, we have to change the minimum to test old TLS versions.
Christian Heimes2875c602021-04-19 07:27:10 +02002804 with warnings_helper.check_warnings():
2805 server_context.minimum_version = min_version
Victor Stinner3ef63442019-02-19 18:06:03 +01002806
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002807 # NOTE: we must enable "ALL" ciphers on the client, otherwise an
2808 # SSLv23 client will send an SSLv3 hello (rather than SSLv2)
2809 # starting from OpenSSL 1.0.0 (see issue #8322).
Christian Heimesa170fa12017-09-15 20:27:30 +02002810 if client_context.protocol == ssl.PROTOCOL_TLS:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002811 client_context.set_ciphers("ALL")
2812
Christian Heimesf6c6b582021-03-18 23:06:50 +01002813 seclevel_workaround(server_context, client_context)
2814
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002815 for ctx in (client_context, server_context):
2816 ctx.verify_mode = certsreqs
Christian Heimesbd5c7d22018-01-20 15:16:30 +01002817 ctx.load_cert_chain(SIGNED_CERTFILE)
2818 ctx.load_verify_locations(SIGNING_CA)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002819 try:
2820 stats = server_params_test(client_context, server_context,
2821 chatty=False, connectionchatty=False)
2822 # Protocol mismatch can result in either an SSLError, or a
2823 # "Connection reset by peer" error.
2824 except ssl.SSLError:
2825 if expect_success:
2826 raise
2827 except OSError as e:
2828 if expect_success or e.errno != errno.ECONNRESET:
2829 raise
2830 else:
2831 if not expect_success:
2832 raise AssertionError(
2833 "Client protocol %s succeeded with server protocol %s!"
2834 % (ssl.get_protocol_name(client_protocol),
2835 ssl.get_protocol_name(server_protocol)))
2836 elif (expect_success is not True
2837 and expect_success != stats['version']):
2838 raise AssertionError("version mismatch: expected %r, got %r"
2839 % (expect_success, stats['version']))
2840
2841
2842class ThreadedTests(unittest.TestCase):
2843
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002844 def test_echo(self):
2845 """Basic test of an SSL client connecting to a server"""
2846 if support.verbose:
2847 sys.stdout.write("\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002848
Christian Heimesa170fa12017-09-15 20:27:30 +02002849 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002850
2851 with self.subTest(client=ssl.PROTOCOL_TLS_CLIENT, server=ssl.PROTOCOL_TLS_SERVER):
2852 server_params_test(client_context=client_context,
2853 server_context=server_context,
2854 chatty=True, connectionchatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02002855 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002856
2857 client_context.check_hostname = False
2858 with self.subTest(client=ssl.PROTOCOL_TLS_SERVER, server=ssl.PROTOCOL_TLS_CLIENT):
2859 with self.assertRaises(ssl.SSLError) as e:
2860 server_params_test(client_context=server_context,
2861 server_context=client_context,
2862 chatty=True, connectionchatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02002863 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002864 self.assertIn('called a function you should not call',
2865 str(e.exception))
2866
2867 with self.subTest(client=ssl.PROTOCOL_TLS_SERVER, server=ssl.PROTOCOL_TLS_SERVER):
2868 with self.assertRaises(ssl.SSLError) as e:
2869 server_params_test(client_context=server_context,
2870 server_context=server_context,
2871 chatty=True, connectionchatty=True)
2872 self.assertIn('called a function you should not call',
2873 str(e.exception))
2874
2875 with self.subTest(client=ssl.PROTOCOL_TLS_CLIENT, server=ssl.PROTOCOL_TLS_CLIENT):
2876 with self.assertRaises(ssl.SSLError) as e:
2877 server_params_test(client_context=server_context,
2878 server_context=client_context,
2879 chatty=True, connectionchatty=True)
2880 self.assertIn('called a function you should not call',
2881 str(e.exception))
2882
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002883 def test_getpeercert(self):
2884 if support.verbose:
2885 sys.stdout.write("\n")
Christian Heimesa170fa12017-09-15 20:27:30 +02002886
2887 client_context, server_context, hostname = testing_context()
2888 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002889 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002890 with client_context.wrap_socket(socket.socket(),
2891 do_handshake_on_connect=False,
2892 server_hostname=hostname) as s:
2893 s.connect((HOST, server.port))
2894 # getpeercert() raise ValueError while the handshake isn't
2895 # done.
2896 with self.assertRaises(ValueError):
2897 s.getpeercert()
2898 s.do_handshake()
2899 cert = s.getpeercert()
2900 self.assertTrue(cert, "Can't get peer certificate.")
2901 cipher = s.cipher()
2902 if support.verbose:
2903 sys.stdout.write(pprint.pformat(cert) + '\n')
2904 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
2905 if 'subject' not in cert:
2906 self.fail("No subject field in certificate: %s." %
2907 pprint.pformat(cert))
2908 if ((('organizationName', 'Python Software Foundation'),)
2909 not in cert['subject']):
2910 self.fail(
2911 "Missing or invalid 'organizationName' field in certificate subject; "
2912 "should be 'Python Software Foundation'.")
2913 self.assertIn('notBefore', cert)
2914 self.assertIn('notAfter', cert)
2915 before = ssl.cert_time_to_seconds(cert['notBefore'])
2916 after = ssl.cert_time_to_seconds(cert['notAfter'])
2917 self.assertLess(before, after)
Bill Janssen58afe4c2008-09-08 16:45:19 +00002918
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002919 def test_crl_check(self):
2920 if support.verbose:
2921 sys.stdout.write("\n")
2922
Christian Heimesa170fa12017-09-15 20:27:30 +02002923 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002924
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002925 tf = getattr(ssl, "VERIFY_X509_TRUSTED_FIRST", 0)
Christian Heimesa170fa12017-09-15 20:27:30 +02002926 self.assertEqual(client_context.verify_flags, ssl.VERIFY_DEFAULT | tf)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002927
2928 # VERIFY_DEFAULT should pass
2929 server = ThreadedEchoServer(context=server_context, chatty=True)
2930 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002931 with client_context.wrap_socket(socket.socket(),
2932 server_hostname=hostname) as s:
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002933 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002934 cert = s.getpeercert()
2935 self.assertTrue(cert, "Can't get peer certificate.")
Bill Janssen58afe4c2008-09-08 16:45:19 +00002936
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002937 # VERIFY_CRL_CHECK_LEAF without a loaded CRL file fails
Christian Heimesa170fa12017-09-15 20:27:30 +02002938 client_context.verify_flags |= ssl.VERIFY_CRL_CHECK_LEAF
Bill Janssen58afe4c2008-09-08 16:45:19 +00002939
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002940 server = ThreadedEchoServer(context=server_context, chatty=True)
2941 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002942 with client_context.wrap_socket(socket.socket(),
2943 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002944 with self.assertRaisesRegex(ssl.SSLError,
2945 "certificate verify failed"):
2946 s.connect((HOST, server.port))
Bill Janssen58afe4c2008-09-08 16:45:19 +00002947
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002948 # now load a CRL file. The CRL file is signed by the CA.
Christian Heimesa170fa12017-09-15 20:27:30 +02002949 client_context.load_verify_locations(CRLFILE)
Bill Janssen58afe4c2008-09-08 16:45:19 +00002950
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002951 server = ThreadedEchoServer(context=server_context, chatty=True)
2952 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002953 with client_context.wrap_socket(socket.socket(),
2954 server_hostname=hostname) as s:
Antoine Pitroub4bebda2014-04-29 10:03:28 +02002955 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002956 cert = s.getpeercert()
2957 self.assertTrue(cert, "Can't get peer certificate.")
Antoine Pitroub4bebda2014-04-29 10:03:28 +02002958
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002959 def test_check_hostname(self):
2960 if support.verbose:
2961 sys.stdout.write("\n")
Antoine Pitroub4bebda2014-04-29 10:03:28 +02002962
Christian Heimesa170fa12017-09-15 20:27:30 +02002963 client_context, server_context, hostname = testing_context()
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00002964
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002965 # correct hostname should verify
2966 server = ThreadedEchoServer(context=server_context, chatty=True)
2967 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002968 with client_context.wrap_socket(socket.socket(),
2969 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002970 s.connect((HOST, server.port))
2971 cert = s.getpeercert()
2972 self.assertTrue(cert, "Can't get peer certificate.")
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00002973
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002974 # incorrect hostname should raise an exception
2975 server = ThreadedEchoServer(context=server_context, chatty=True)
2976 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002977 with client_context.wrap_socket(socket.socket(),
2978 server_hostname="invalid") as s:
Christian Heimes61d478c2018-01-27 15:51:38 +01002979 with self.assertRaisesRegex(
2980 ssl.CertificateError,
2981 "Hostname mismatch, certificate is not valid for 'invalid'."):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002982 s.connect((HOST, server.port))
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00002983
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002984 # missing server_hostname arg should cause an exception, too
2985 server = ThreadedEchoServer(context=server_context, chatty=True)
2986 with server:
2987 with socket.socket() as s:
2988 with self.assertRaisesRegex(ValueError,
2989 "check_hostname requires server_hostname"):
Christian Heimesa170fa12017-09-15 20:27:30 +02002990 client_context.wrap_socket(s)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002991
Christian Heimesb467d9a2021-04-17 10:07:19 +02002992 @unittest.skipUnless(
2993 ssl.HAS_NEVER_CHECK_COMMON_NAME, "test requires hostname_checks_common_name"
2994 )
2995 def test_hostname_checks_common_name(self):
2996 client_context, server_context, hostname = testing_context()
2997 assert client_context.hostname_checks_common_name
2998 client_context.hostname_checks_common_name = False
2999
3000 # default cert has a SAN
3001 server = ThreadedEchoServer(context=server_context, chatty=True)
3002 with server:
3003 with client_context.wrap_socket(socket.socket(),
3004 server_hostname=hostname) as s:
3005 s.connect((HOST, server.port))
3006
3007 client_context, server_context, hostname = testing_context(NOSANFILE)
3008 client_context.hostname_checks_common_name = False
3009 server = ThreadedEchoServer(context=server_context, chatty=True)
3010 with server:
3011 with client_context.wrap_socket(socket.socket(),
3012 server_hostname=hostname) as s:
3013 with self.assertRaises(ssl.SSLCertVerificationError):
3014 s.connect((HOST, server.port))
3015
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003016 def test_ecc_cert(self):
3017 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3018 client_context.load_verify_locations(SIGNING_CA)
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003019 client_context.set_ciphers('ECDHE:ECDSA:!NULL:!aRSA')
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003020 hostname = SIGNED_CERTFILE_ECC_HOSTNAME
3021
3022 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3023 # load ECC cert
3024 server_context.load_cert_chain(SIGNED_CERTFILE_ECC)
3025
3026 # correct hostname should verify
3027 server = ThreadedEchoServer(context=server_context, chatty=True)
3028 with server:
3029 with client_context.wrap_socket(socket.socket(),
3030 server_hostname=hostname) as s:
3031 s.connect((HOST, server.port))
3032 cert = s.getpeercert()
3033 self.assertTrue(cert, "Can't get peer certificate.")
3034 cipher = s.cipher()[0].split('-')
3035 self.assertTrue(cipher[:2], ('ECDHE', 'ECDSA'))
3036
3037 def test_dual_rsa_ecc(self):
3038 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3039 client_context.load_verify_locations(SIGNING_CA)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003040 # TODO: fix TLSv1.3 once SSLContext can restrict signature
3041 # algorithms.
3042 client_context.options |= ssl.OP_NO_TLSv1_3
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003043 # only ECDSA certs
3044 client_context.set_ciphers('ECDHE:ECDSA:!NULL:!aRSA')
3045 hostname = SIGNED_CERTFILE_ECC_HOSTNAME
3046
3047 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3048 # load ECC and RSA key/cert pairs
3049 server_context.load_cert_chain(SIGNED_CERTFILE_ECC)
3050 server_context.load_cert_chain(SIGNED_CERTFILE)
3051
3052 # correct hostname should verify
3053 server = ThreadedEchoServer(context=server_context, chatty=True)
3054 with server:
3055 with client_context.wrap_socket(socket.socket(),
3056 server_hostname=hostname) as s:
3057 s.connect((HOST, server.port))
3058 cert = s.getpeercert()
3059 self.assertTrue(cert, "Can't get peer certificate.")
3060 cipher = s.cipher()[0].split('-')
3061 self.assertTrue(cipher[:2], ('ECDHE', 'ECDSA'))
3062
Christian Heimes66e57422018-01-29 14:25:13 +01003063 def test_check_hostname_idn(self):
3064 if support.verbose:
3065 sys.stdout.write("\n")
3066
Christian Heimes11a14932018-02-24 02:35:08 +01003067 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimes66e57422018-01-29 14:25:13 +01003068 server_context.load_cert_chain(IDNSANSFILE)
3069
Christian Heimes11a14932018-02-24 02:35:08 +01003070 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes66e57422018-01-29 14:25:13 +01003071 context.verify_mode = ssl.CERT_REQUIRED
3072 context.check_hostname = True
3073 context.load_verify_locations(SIGNING_CA)
3074
3075 # correct hostname should verify, when specified in several
3076 # different ways
3077 idn_hostnames = [
3078 ('könig.idn.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003079 'xn--knig-5qa.idn.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003080 ('xn--knig-5qa.idn.pythontest.net',
3081 'xn--knig-5qa.idn.pythontest.net'),
3082 (b'xn--knig-5qa.idn.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003083 'xn--knig-5qa.idn.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003084
3085 ('königsgäßchen.idna2003.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003086 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003087 ('xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
3088 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
3089 (b'xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003090 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
3091
3092 # ('königsgäßchen.idna2008.pythontest.net',
3093 # 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3094 ('xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
3095 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3096 (b'xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
3097 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3098
Christian Heimes66e57422018-01-29 14:25:13 +01003099 ]
3100 for server_hostname, expected_hostname in idn_hostnames:
3101 server = ThreadedEchoServer(context=server_context, chatty=True)
3102 with server:
3103 with context.wrap_socket(socket.socket(),
3104 server_hostname=server_hostname) as s:
3105 self.assertEqual(s.server_hostname, expected_hostname)
3106 s.connect((HOST, server.port))
3107 cert = s.getpeercert()
3108 self.assertEqual(s.server_hostname, expected_hostname)
3109 self.assertTrue(cert, "Can't get peer certificate.")
3110
Christian Heimes66e57422018-01-29 14:25:13 +01003111 # incorrect hostname should raise an exception
3112 server = ThreadedEchoServer(context=server_context, chatty=True)
3113 with server:
3114 with context.wrap_socket(socket.socket(),
3115 server_hostname="python.example.org") as s:
3116 with self.assertRaises(ssl.CertificateError):
3117 s.connect((HOST, server.port))
3118
Christian Heimes529525f2018-05-23 22:24:45 +02003119 def test_wrong_cert_tls12(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003120 """Connecting when the server rejects the client's certificate
3121
3122 Launch a server with CERT_REQUIRED, and check that trying to
3123 connect to it with a wrong client certificate fails.
3124 """
Christian Heimes05d9fe32018-02-27 08:55:39 +01003125 client_context, server_context, hostname = testing_context()
Christian Heimes88bfd0b2018-08-14 12:54:19 +02003126 # load client cert that is not signed by trusted CA
3127 client_context.load_cert_chain(CERTFILE)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003128 # require TLS client authentication
3129 server_context.verify_mode = ssl.CERT_REQUIRED
Christian Heimes529525f2018-05-23 22:24:45 +02003130 # TLS 1.3 has different handshake
3131 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimes05d9fe32018-02-27 08:55:39 +01003132
3133 server = ThreadedEchoServer(
3134 context=server_context, chatty=True, connectionchatty=True,
3135 )
3136
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003137 with server, \
Christian Heimes05d9fe32018-02-27 08:55:39 +01003138 client_context.wrap_socket(socket.socket(),
3139 server_hostname=hostname) as s:
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003140 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003141 # Expect either an SSL error about the server rejecting
3142 # the connection, or a low-level connection reset (which
3143 # sometimes happens on Windows)
3144 s.connect((HOST, server.port))
3145 except ssl.SSLError as e:
3146 if support.verbose:
3147 sys.stdout.write("\nSSLError is %r\n" % e)
3148 except OSError as e:
3149 if e.errno != errno.ECONNRESET:
3150 raise
3151 if support.verbose:
3152 sys.stdout.write("\nsocket.error is %r\n" % e)
3153 else:
3154 self.fail("Use of invalid cert should have failed!")
3155
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003156 @requires_tls_version('TLSv1_3')
Christian Heimes529525f2018-05-23 22:24:45 +02003157 def test_wrong_cert_tls13(self):
3158 client_context, server_context, hostname = testing_context()
Christian Heimes88bfd0b2018-08-14 12:54:19 +02003159 # load client cert that is not signed by trusted CA
3160 client_context.load_cert_chain(CERTFILE)
Christian Heimes529525f2018-05-23 22:24:45 +02003161 server_context.verify_mode = ssl.CERT_REQUIRED
3162 server_context.minimum_version = ssl.TLSVersion.TLSv1_3
3163 client_context.minimum_version = ssl.TLSVersion.TLSv1_3
3164
3165 server = ThreadedEchoServer(
3166 context=server_context, chatty=True, connectionchatty=True,
3167 )
3168 with server, \
3169 client_context.wrap_socket(socket.socket(),
3170 server_hostname=hostname) as s:
3171 # TLS 1.3 perform client cert exchange after handshake
3172 s.connect((HOST, server.port))
3173 try:
3174 s.write(b'data')
Christian Heimese0472392021-04-23 20:03:25 +02003175 s.read(1000)
3176 s.write(b'should have failed already')
3177 s.read(1000)
Christian Heimes529525f2018-05-23 22:24:45 +02003178 except ssl.SSLError as e:
3179 if support.verbose:
3180 sys.stdout.write("\nSSLError is %r\n" % e)
3181 except OSError as e:
3182 if e.errno != errno.ECONNRESET:
3183 raise
3184 if support.verbose:
3185 sys.stdout.write("\nsocket.error is %r\n" % e)
3186 else:
Christian Heimese0472392021-04-23 20:03:25 +02003187 if sys.platform == "win32":
3188 self.skipTest(
3189 "Ignoring failed test_wrong_cert_tls13 test case. "
3190 "The test is flaky on Windows, see bpo-43921."
3191 )
3192 else:
3193 self.fail("Use of invalid cert should have failed!")
Christian Heimes529525f2018-05-23 22:24:45 +02003194
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003195 def test_rude_shutdown(self):
3196 """A brutal shutdown of an SSL server should raise an OSError
3197 in the client when attempting handshake.
3198 """
3199 listener_ready = threading.Event()
3200 listener_gone = threading.Event()
3201
3202 s = socket.socket()
Serhiy Storchaka16994912020-04-25 10:06:29 +03003203 port = socket_helper.bind_port(s, HOST)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003204
3205 # `listener` runs in a thread. It sits in an accept() until
3206 # the main thread connects. Then it rudely closes the socket,
3207 # and sets Event `listener_gone` to let the main thread know
3208 # the socket is gone.
3209 def listener():
3210 s.listen()
3211 listener_ready.set()
3212 newsock, addr = s.accept()
3213 newsock.close()
3214 s.close()
3215 listener_gone.set()
3216
3217 def connector():
3218 listener_ready.wait()
3219 with socket.socket() as c:
3220 c.connect((HOST, port))
3221 listener_gone.wait()
Antoine Pitrou40f08742010-04-24 22:04:40 +00003222 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003223 ssl_sock = test_wrap_socket(c)
3224 except OSError:
3225 pass
3226 else:
3227 self.fail('connecting to closed SSL socket should have failed')
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003228
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003229 t = threading.Thread(target=listener)
3230 t.start()
3231 try:
3232 connector()
3233 finally:
Antoine Pitrou5c89b4e2012-11-11 01:25:36 +01003234 t.join()
Antoine Pitrou5c89b4e2012-11-11 01:25:36 +01003235
Christian Heimesb3ad0e52017-09-08 12:00:19 -07003236 def test_ssl_cert_verify_error(self):
3237 if support.verbose:
3238 sys.stdout.write("\n")
3239
3240 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3241 server_context.load_cert_chain(SIGNED_CERTFILE)
3242
3243 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3244
3245 server = ThreadedEchoServer(context=server_context, chatty=True)
3246 with server:
3247 with context.wrap_socket(socket.socket(),
Christian Heimesa170fa12017-09-15 20:27:30 +02003248 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Christian Heimesb3ad0e52017-09-08 12:00:19 -07003249 try:
3250 s.connect((HOST, server.port))
3251 except ssl.SSLError as e:
3252 msg = 'unable to get local issuer certificate'
3253 self.assertIsInstance(e, ssl.SSLCertVerificationError)
3254 self.assertEqual(e.verify_code, 20)
3255 self.assertEqual(e.verify_message, msg)
3256 self.assertIn(msg, repr(e))
3257 self.assertIn('certificate verify failed', repr(e))
3258
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003259 @requires_tls_version('SSLv2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003260 def test_protocol_sslv2(self):
3261 """Connecting to an SSLv2 server with various client options"""
3262 if support.verbose:
3263 sys.stdout.write("\n")
3264 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
3265 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
3266 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
Christian Heimesa170fa12017-09-15 20:27:30 +02003267 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003268 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003269 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
3270 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
3271 # SSLv23 client with specific SSL options
Christian Heimesa170fa12017-09-15 20:27:30 +02003272 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003273 client_options=ssl.OP_NO_SSLv3)
Christian Heimesa170fa12017-09-15 20:27:30 +02003274 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003275 client_options=ssl.OP_NO_TLSv1)
Antoine Pitrou242db722013-05-01 20:52:07 +02003276
Christian Heimesa170fa12017-09-15 20:27:30 +02003277 def test_PROTOCOL_TLS(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003278 """Connecting to an SSLv23 server with various client options"""
3279 if support.verbose:
3280 sys.stdout.write("\n")
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003281 if has_tls_version('SSLv2'):
Antoine Pitrou8f85f902012-01-03 22:46:48 +01003282 try:
Christian Heimesa170fa12017-09-15 20:27:30 +02003283 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv2, True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003284 except OSError as x:
3285 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
3286 if support.verbose:
3287 sys.stdout.write(
3288 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
3289 % str(x))
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003290 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003291 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False)
3292 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003293 if has_tls_version('TLSv1'):
3294 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1')
Antoine Pitrou8f85f902012-01-03 22:46:48 +01003295
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003296 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003297 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False, ssl.CERT_OPTIONAL)
3298 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True, ssl.CERT_OPTIONAL)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003299 if has_tls_version('TLSv1'):
3300 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003301
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003302 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003303 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False, ssl.CERT_REQUIRED)
3304 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True, ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003305 if has_tls_version('TLSv1'):
3306 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003307
3308 # Server with specific SSL options
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003309 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003310 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003311 server_options=ssl.OP_NO_SSLv3)
3312 # Will choose TLSv1
Christian Heimesa170fa12017-09-15 20:27:30 +02003313 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003314 server_options=ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003315 if has_tls_version('TLSv1'):
3316 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, False,
3317 server_options=ssl.OP_NO_TLSv1)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003318
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003319 @requires_tls_version('SSLv3')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003320 def test_protocol_sslv3(self):
3321 """Connecting to an SSLv3 server with various client options"""
3322 if support.verbose:
3323 sys.stdout.write("\n")
3324 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3')
3325 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_OPTIONAL)
3326 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003327 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003328 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003329 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003330 client_options=ssl.OP_NO_SSLv3)
3331 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003332
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003333 @requires_tls_version('TLSv1')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003334 def test_protocol_tlsv1(self):
3335 """Connecting to a TLSv1 server with various client options"""
3336 if support.verbose:
3337 sys.stdout.write("\n")
3338 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1')
3339 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL)
3340 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003341 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003342 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003343 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003344 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003345 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003346 client_options=ssl.OP_NO_TLSv1)
3347
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003348 @requires_tls_version('TLSv1_1')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003349 def test_protocol_tlsv1_1(self):
3350 """Connecting to a TLSv1.1 server with various client options.
3351 Testing against older TLS versions."""
3352 if support.verbose:
3353 sys.stdout.write("\n")
3354 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1')
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003355 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003356 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003357 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003358 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003359 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003360 client_options=ssl.OP_NO_TLSv1_1)
3361
Christian Heimesa170fa12017-09-15 20:27:30 +02003362 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1')
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003363 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False)
3364 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003365
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003366 @requires_tls_version('TLSv1_2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003367 def test_protocol_tlsv1_2(self):
3368 """Connecting to a TLSv1.2 server with various client options.
3369 Testing against older TLS versions."""
3370 if support.verbose:
3371 sys.stdout.write("\n")
3372 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2',
3373 server_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,
3374 client_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003375 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003376 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003377 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003378 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003379 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003380 client_options=ssl.OP_NO_TLSv1_2)
3381
Christian Heimesa170fa12017-09-15 20:27:30 +02003382 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003383 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1, False)
3384 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_2, False)
3385 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False)
3386 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False)
3387
3388 def test_starttls(self):
3389 """Switching from clear text to encrypted and back again."""
3390 msgs = (b"msg 1", b"MSG 2", b"STARTTLS", b"MSG 3", b"msg 4", b"ENDTLS", b"msg 5", b"msg 6")
3391
3392 server = ThreadedEchoServer(CERTFILE,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003393 starttls_server=True,
3394 chatty=True,
3395 connectionchatty=True)
3396 wrapped = False
3397 with server:
3398 s = socket.socket()
Serhiy Storchaka5eca7f32019-09-01 12:12:52 +03003399 s.setblocking(True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003400 s.connect((HOST, server.port))
Antoine Pitroud6494802011-07-21 01:11:30 +02003401 if support.verbose:
3402 sys.stdout.write("\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003403 for indata in msgs:
Antoine Pitroud6494802011-07-21 01:11:30 +02003404 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003405 sys.stdout.write(
3406 " client: sending %r...\n" % indata)
3407 if wrapped:
3408 conn.write(indata)
3409 outdata = conn.read()
3410 else:
3411 s.send(indata)
3412 outdata = s.recv(1024)
3413 msg = outdata.strip().lower()
3414 if indata == b"STARTTLS" and msg.startswith(b"ok"):
3415 # STARTTLS ok, switch to secure mode
3416 if support.verbose:
3417 sys.stdout.write(
3418 " client: read %r from server, starting TLS...\n"
3419 % msg)
Christian Heimesa170fa12017-09-15 20:27:30 +02003420 conn = test_wrap_socket(s)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003421 wrapped = True
3422 elif indata == b"ENDTLS" and msg.startswith(b"ok"):
3423 # ENDTLS ok, switch back to clear text
3424 if support.verbose:
3425 sys.stdout.write(
3426 " client: read %r from server, ending TLS...\n"
3427 % msg)
3428 s = conn.unwrap()
3429 wrapped = False
3430 else:
3431 if support.verbose:
3432 sys.stdout.write(
3433 " client: read %r from server\n" % msg)
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003434 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003435 sys.stdout.write(" client: closing connection.\n")
3436 if wrapped:
3437 conn.write(b"over\n")
3438 else:
3439 s.send(b"over\n")
3440 if wrapped:
3441 conn.close()
3442 else:
3443 s.close()
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003444
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003445 def test_socketserver(self):
3446 """Using socketserver to create and manage SSL connections."""
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003447 server = make_https_server(self, certfile=SIGNED_CERTFILE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003448 # try to connect
3449 if support.verbose:
3450 sys.stdout.write('\n')
3451 with open(CERTFILE, 'rb') as f:
3452 d1 = f.read()
3453 d2 = ''
3454 # now fetch the same data from the HTTPS server
3455 url = 'https://localhost:%d/%s' % (
3456 server.port, os.path.split(CERTFILE)[1])
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003457 context = ssl.create_default_context(cafile=SIGNING_CA)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003458 f = urllib.request.urlopen(url, context=context)
3459 try:
3460 dlen = f.info().get("content-length")
3461 if dlen and (int(dlen) > 0):
3462 d2 = f.read(int(dlen))
3463 if support.verbose:
3464 sys.stdout.write(
3465 " client: read %d bytes from remote server '%s'\n"
3466 % (len(d2), server))
3467 finally:
3468 f.close()
3469 self.assertEqual(d1, d2)
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003470
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003471 def test_asyncore_server(self):
3472 """Check the example asyncore integration."""
3473 if support.verbose:
3474 sys.stdout.write("\n")
Antoine Pitrou0e576f12011-12-22 10:03:38 +01003475
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003476 indata = b"FOO\n"
3477 server = AsyncoreEchoServer(CERTFILE)
3478 with server:
3479 s = test_wrap_socket(socket.socket())
3480 s.connect(('127.0.0.1', server.port))
3481 if support.verbose:
3482 sys.stdout.write(
3483 " client: sending %r...\n" % indata)
3484 s.write(indata)
3485 outdata = s.read()
3486 if support.verbose:
3487 sys.stdout.write(" client: read %r\n" % outdata)
3488 if outdata != indata.lower():
3489 self.fail(
3490 "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
3491 % (outdata[:20], len(outdata),
3492 indata[:20].lower(), len(indata)))
3493 s.write(b"over\n")
3494 if support.verbose:
3495 sys.stdout.write(" client: closing connection.\n")
3496 s.close()
3497 if support.verbose:
3498 sys.stdout.write(" client: connection closed.\n")
Benjamin Petersoncca27322015-01-23 16:35:37 -05003499
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003500 def test_recv_send(self):
3501 """Test recv(), send() and friends."""
3502 if support.verbose:
3503 sys.stdout.write("\n")
3504
3505 server = ThreadedEchoServer(CERTFILE,
3506 certreqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003507 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003508 cacerts=CERTFILE,
3509 chatty=True,
3510 connectionchatty=False)
3511 with server:
3512 s = test_wrap_socket(socket.socket(),
3513 server_side=False,
3514 certfile=CERTFILE,
3515 ca_certs=CERTFILE,
Christian Heimes2875c602021-04-19 07:27:10 +02003516 cert_reqs=ssl.CERT_NONE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003517 s.connect((HOST, server.port))
3518 # helper methods for standardising recv* method signatures
3519 def _recv_into():
3520 b = bytearray(b"\0"*100)
3521 count = s.recv_into(b)
3522 return b[:count]
3523
3524 def _recvfrom_into():
3525 b = bytearray(b"\0"*100)
3526 count, addr = s.recvfrom_into(b)
3527 return b[:count]
3528
3529 # (name, method, expect success?, *args, return value func)
3530 send_methods = [
3531 ('send', s.send, True, [], len),
3532 ('sendto', s.sendto, False, ["some.address"], len),
3533 ('sendall', s.sendall, True, [], lambda x: None),
3534 ]
3535 # (name, method, whether to expect success, *args)
3536 recv_methods = [
3537 ('recv', s.recv, True, []),
3538 ('recvfrom', s.recvfrom, False, ["some.address"]),
3539 ('recv_into', _recv_into, True, []),
3540 ('recvfrom_into', _recvfrom_into, False, []),
3541 ]
3542 data_prefix = "PREFIX_"
3543
3544 for (meth_name, send_meth, expect_success, args,
3545 ret_val_meth) in send_methods:
3546 indata = (data_prefix + meth_name).encode('ascii')
3547 try:
3548 ret = send_meth(indata, *args)
3549 msg = "sending with {}".format(meth_name)
3550 self.assertEqual(ret, ret_val_meth(indata), msg=msg)
3551 outdata = s.read()
3552 if outdata != indata.lower():
3553 self.fail(
3554 "While sending with <<{name:s}>> bad data "
3555 "<<{outdata:r}>> ({nout:d}) received; "
3556 "expected <<{indata:r}>> ({nin:d})\n".format(
3557 name=meth_name, outdata=outdata[:20],
3558 nout=len(outdata),
3559 indata=indata[:20], nin=len(indata)
3560 )
3561 )
3562 except ValueError as e:
3563 if expect_success:
3564 self.fail(
3565 "Failed to send with method <<{name:s}>>; "
3566 "expected to succeed.\n".format(name=meth_name)
3567 )
3568 if not str(e).startswith(meth_name):
3569 self.fail(
3570 "Method <<{name:s}>> failed with unexpected "
3571 "exception message: {exp:s}\n".format(
3572 name=meth_name, exp=e
3573 )
3574 )
3575
3576 for meth_name, recv_meth, expect_success, args in recv_methods:
3577 indata = (data_prefix + meth_name).encode('ascii')
3578 try:
3579 s.send(indata)
3580 outdata = recv_meth(*args)
3581 if outdata != indata.lower():
3582 self.fail(
3583 "While receiving with <<{name:s}>> bad data "
3584 "<<{outdata:r}>> ({nout:d}) received; "
3585 "expected <<{indata:r}>> ({nin:d})\n".format(
3586 name=meth_name, outdata=outdata[:20],
3587 nout=len(outdata),
3588 indata=indata[:20], nin=len(indata)
3589 )
3590 )
3591 except ValueError as e:
3592 if expect_success:
3593 self.fail(
3594 "Failed to receive with method <<{name:s}>>; "
3595 "expected to succeed.\n".format(name=meth_name)
3596 )
3597 if not str(e).startswith(meth_name):
3598 self.fail(
3599 "Method <<{name:s}>> failed with unexpected "
3600 "exception message: {exp:s}\n".format(
3601 name=meth_name, exp=e
3602 )
3603 )
3604 # consume data
3605 s.read()
3606
3607 # read(-1, buffer) is supported, even though read(-1) is not
3608 data = b"data"
3609 s.send(data)
3610 buffer = bytearray(len(data))
3611 self.assertEqual(s.read(-1, buffer), len(data))
3612 self.assertEqual(buffer, data)
3613
Christian Heimes888bbdc2017-09-07 14:18:21 -07003614 # sendall accepts bytes-like objects
3615 if ctypes is not None:
3616 ubyte = ctypes.c_ubyte * len(data)
3617 byteslike = ubyte.from_buffer_copy(data)
3618 s.sendall(byteslike)
3619 self.assertEqual(s.read(), data)
3620
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003621 # Make sure sendmsg et al are disallowed to avoid
3622 # inadvertent disclosure of data and/or corruption
3623 # of the encrypted data stream
Serhiy Storchaka42b1d612018-12-06 22:36:55 +02003624 self.assertRaises(NotImplementedError, s.dup)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003625 self.assertRaises(NotImplementedError, s.sendmsg, [b"data"])
3626 self.assertRaises(NotImplementedError, s.recvmsg, 100)
3627 self.assertRaises(NotImplementedError,
Serhiy Storchaka42b1d612018-12-06 22:36:55 +02003628 s.recvmsg_into, [bytearray(100)])
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003629 s.write(b"over\n")
3630
3631 self.assertRaises(ValueError, s.recv, -1)
3632 self.assertRaises(ValueError, s.read, -1)
3633
3634 s.close()
3635
3636 def test_recv_zero(self):
3637 server = ThreadedEchoServer(CERTFILE)
3638 server.__enter__()
3639 self.addCleanup(server.__exit__, None, None)
3640 s = socket.create_connection((HOST, server.port))
3641 self.addCleanup(s.close)
3642 s = test_wrap_socket(s, suppress_ragged_eofs=False)
3643 self.addCleanup(s.close)
3644
3645 # recv/read(0) should return no data
3646 s.send(b"data")
3647 self.assertEqual(s.recv(0), b"")
3648 self.assertEqual(s.read(0), b"")
3649 self.assertEqual(s.read(), b"data")
3650
3651 # Should not block if the other end sends no data
3652 s.setblocking(False)
3653 self.assertEqual(s.recv(0), b"")
3654 self.assertEqual(s.recv_into(bytearray()), 0)
3655
3656 def test_nonblocking_send(self):
3657 server = ThreadedEchoServer(CERTFILE,
3658 certreqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003659 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003660 cacerts=CERTFILE,
3661 chatty=True,
3662 connectionchatty=False)
3663 with server:
3664 s = test_wrap_socket(socket.socket(),
3665 server_side=False,
3666 certfile=CERTFILE,
3667 ca_certs=CERTFILE,
Christian Heimes2875c602021-04-19 07:27:10 +02003668 cert_reqs=ssl.CERT_NONE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003669 s.connect((HOST, server.port))
3670 s.setblocking(False)
3671
3672 # If we keep sending data, at some point the buffers
3673 # will be full and the call will block
3674 buf = bytearray(8192)
3675 def fill_buffer():
3676 while True:
3677 s.send(buf)
3678 self.assertRaises((ssl.SSLWantWriteError,
3679 ssl.SSLWantReadError), fill_buffer)
3680
3681 # Now read all the output and discard it
3682 s.setblocking(True)
3683 s.close()
3684
3685 def test_handshake_timeout(self):
3686 # Issue #5103: SSL handshake must respect the socket timeout
3687 server = socket.socket(socket.AF_INET)
3688 host = "127.0.0.1"
Serhiy Storchaka16994912020-04-25 10:06:29 +03003689 port = socket_helper.bind_port(server)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003690 started = threading.Event()
3691 finish = False
3692
3693 def serve():
3694 server.listen()
3695 started.set()
3696 conns = []
3697 while not finish:
3698 r, w, e = select.select([server], [], [], 0.1)
3699 if server in r:
3700 # Let the socket hang around rather than having
3701 # it closed by garbage collection.
3702 conns.append(server.accept()[0])
3703 for sock in conns:
3704 sock.close()
3705
3706 t = threading.Thread(target=serve)
3707 t.start()
3708 started.wait()
3709
3710 try:
3711 try:
3712 c = socket.socket(socket.AF_INET)
3713 c.settimeout(0.2)
3714 c.connect((host, port))
3715 # Will attempt handshake and time out
Christian Heimes03c8ddd2020-11-20 09:26:07 +01003716 self.assertRaisesRegex(TimeoutError, "timed out",
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003717 test_wrap_socket, c)
3718 finally:
3719 c.close()
3720 try:
3721 c = socket.socket(socket.AF_INET)
3722 c = test_wrap_socket(c)
3723 c.settimeout(0.2)
3724 # Will attempt handshake and time out
Christian Heimes03c8ddd2020-11-20 09:26:07 +01003725 self.assertRaisesRegex(TimeoutError, "timed out",
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003726 c.connect, (host, port))
3727 finally:
3728 c.close()
3729 finally:
3730 finish = True
3731 t.join()
3732 server.close()
3733
3734 def test_server_accept(self):
3735 # Issue #16357: accept() on a SSLSocket created through
3736 # SSLContext.wrap_socket().
Christian Heimes2875c602021-04-19 07:27:10 +02003737 client_ctx, server_ctx, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003738 server = socket.socket(socket.AF_INET)
3739 host = "127.0.0.1"
Serhiy Storchaka16994912020-04-25 10:06:29 +03003740 port = socket_helper.bind_port(server)
Christian Heimes2875c602021-04-19 07:27:10 +02003741 server = server_ctx.wrap_socket(server, server_side=True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003742 self.assertTrue(server.server_side)
3743
3744 evt = threading.Event()
3745 remote = None
3746 peer = None
3747 def serve():
3748 nonlocal remote, peer
3749 server.listen()
3750 # Block on the accept and wait on the connection to close.
3751 evt.set()
3752 remote, peer = server.accept()
Christian Heimes529525f2018-05-23 22:24:45 +02003753 remote.send(remote.recv(4))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003754
3755 t = threading.Thread(target=serve)
3756 t.start()
3757 # Client wait until server setup and perform a connect.
3758 evt.wait()
Christian Heimes2875c602021-04-19 07:27:10 +02003759 client = client_ctx.wrap_socket(
3760 socket.socket(), server_hostname=hostname
3761 )
3762 client.connect((hostname, port))
Christian Heimes529525f2018-05-23 22:24:45 +02003763 client.send(b'data')
3764 client.recv()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003765 client_addr = client.getsockname()
3766 client.close()
3767 t.join()
3768 remote.close()
3769 server.close()
3770 # Sanity checks.
3771 self.assertIsInstance(remote, ssl.SSLSocket)
3772 self.assertEqual(peer, client_addr)
3773
3774 def test_getpeercert_enotconn(self):
Christian Heimes2875c602021-04-19 07:27:10 +02003775 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3776 context.check_hostname = False
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003777 with context.wrap_socket(socket.socket()) as sock:
3778 with self.assertRaises(OSError) as cm:
3779 sock.getpeercert()
3780 self.assertEqual(cm.exception.errno, errno.ENOTCONN)
3781
3782 def test_do_handshake_enotconn(self):
Christian Heimes2875c602021-04-19 07:27:10 +02003783 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3784 context.check_hostname = False
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003785 with context.wrap_socket(socket.socket()) as sock:
3786 with self.assertRaises(OSError) as cm:
3787 sock.do_handshake()
3788 self.assertEqual(cm.exception.errno, errno.ENOTCONN)
3789
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003790 def test_no_shared_ciphers(self):
3791 client_context, server_context, hostname = testing_context()
3792 # OpenSSL enables all TLS 1.3 ciphers, enforce TLS 1.2 for test
3793 client_context.options |= ssl.OP_NO_TLSv1_3
Victor Stinner5e922652018-09-07 17:30:33 +02003794 # Force different suites on client and server
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003795 client_context.set_ciphers("AES128")
3796 server_context.set_ciphers("AES256")
3797 with ThreadedEchoServer(context=server_context) as server:
3798 with client_context.wrap_socket(socket.socket(),
3799 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003800 with self.assertRaises(OSError):
3801 s.connect((HOST, server.port))
3802 self.assertIn("no shared cipher", server.conn_errors[0])
3803
3804 def test_version_basic(self):
3805 """
3806 Basic tests for SSLSocket.version().
3807 More tests are done in the test_protocol_*() methods.
3808 """
Christian Heimesa170fa12017-09-15 20:27:30 +02003809 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3810 context.check_hostname = False
3811 context.verify_mode = ssl.CERT_NONE
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003812 with ThreadedEchoServer(CERTFILE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003813 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003814 chatty=False) as server:
3815 with context.wrap_socket(socket.socket()) as s:
3816 self.assertIs(s.version(), None)
Christian Heimes141c5e82018-02-24 21:10:57 +01003817 self.assertIs(s._sslobj, None)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003818 s.connect((HOST, server.port))
Christian Heimes39258d32021-04-17 11:36:35 +02003819 self.assertEqual(s.version(), 'TLSv1.3')
Christian Heimes141c5e82018-02-24 21:10:57 +01003820 self.assertIs(s._sslobj, None)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003821 self.assertIs(s.version(), None)
3822
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003823 @requires_tls_version('TLSv1_3')
Christian Heimescb5b68a2017-09-07 18:07:00 -07003824 def test_tls1_3(self):
Christian Heimes2875c602021-04-19 07:27:10 +02003825 client_context, server_context, hostname = testing_context()
3826 client_context.minimum_version = ssl.TLSVersion.TLSv1_3
3827 with ThreadedEchoServer(context=server_context) as server:
3828 with client_context.wrap_socket(socket.socket(),
3829 server_hostname=hostname) as s:
Christian Heimescb5b68a2017-09-07 18:07:00 -07003830 s.connect((HOST, server.port))
Christian Heimes05d9fe32018-02-27 08:55:39 +01003831 self.assertIn(s.cipher()[0], {
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003832 'TLS_AES_256_GCM_SHA384',
3833 'TLS_CHACHA20_POLY1305_SHA256',
3834 'TLS_AES_128_GCM_SHA256',
Christian Heimes05d9fe32018-02-27 08:55:39 +01003835 })
3836 self.assertEqual(s.version(), 'TLSv1.3')
Christian Heimescb5b68a2017-09-07 18:07:00 -07003837
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003838 @requires_tls_version('TLSv1_2')
Christian Heimes2875c602021-04-19 07:27:10 +02003839 @requires_tls_version('TLSv1')
3840 @ignore_deprecation
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003841 def test_min_max_version_tlsv1_2(self):
Christian Heimes698dde12018-02-27 11:54:43 +01003842 client_context, server_context, hostname = testing_context()
3843 # client TLSv1.0 to 1.2
3844 client_context.minimum_version = ssl.TLSVersion.TLSv1
3845 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
3846 # server only TLSv1.2
3847 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
3848 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
3849
3850 with ThreadedEchoServer(context=server_context) as server:
3851 with client_context.wrap_socket(socket.socket(),
3852 server_hostname=hostname) as s:
3853 s.connect((HOST, server.port))
3854 self.assertEqual(s.version(), 'TLSv1.2')
3855
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003856 @requires_tls_version('TLSv1_1')
Christian Heimes2875c602021-04-19 07:27:10 +02003857 @ignore_deprecation
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003858 def test_min_max_version_tlsv1_1(self):
3859 client_context, server_context, hostname = testing_context()
Christian Heimes698dde12018-02-27 11:54:43 +01003860 # client 1.0 to 1.2, server 1.0 to 1.1
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003861 client_context.minimum_version = ssl.TLSVersion.TLSv1
3862 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimes698dde12018-02-27 11:54:43 +01003863 server_context.minimum_version = ssl.TLSVersion.TLSv1
3864 server_context.maximum_version = ssl.TLSVersion.TLSv1_1
Christian Heimesf6c6b582021-03-18 23:06:50 +01003865 seclevel_workaround(client_context, server_context)
Christian Heimes698dde12018-02-27 11:54:43 +01003866
3867 with ThreadedEchoServer(context=server_context) as server:
3868 with client_context.wrap_socket(socket.socket(),
3869 server_hostname=hostname) as s:
3870 s.connect((HOST, server.port))
3871 self.assertEqual(s.version(), 'TLSv1.1')
3872
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003873 @requires_tls_version('TLSv1_2')
Christian Heimesce04e712020-11-18 13:10:53 +01003874 @requires_tls_version('TLSv1')
Christian Heimes2875c602021-04-19 07:27:10 +02003875 @ignore_deprecation
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003876 def test_min_max_version_mismatch(self):
3877 client_context, server_context, hostname = testing_context()
Christian Heimes698dde12018-02-27 11:54:43 +01003878 # client 1.0, server 1.2 (mismatch)
Christian Heimes698dde12018-02-27 11:54:43 +01003879 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesc9bc49c2019-09-11 19:24:47 +02003880 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
Christian Heimese35d1ba2019-06-03 20:40:15 +02003881 client_context.maximum_version = ssl.TLSVersion.TLSv1
Christian Heimesde606ea2019-09-11 19:48:58 +02003882 client_context.minimum_version = ssl.TLSVersion.TLSv1
Christian Heimesf6c6b582021-03-18 23:06:50 +01003883 seclevel_workaround(client_context, server_context)
3884
Christian Heimes698dde12018-02-27 11:54:43 +01003885 with ThreadedEchoServer(context=server_context) as server:
3886 with client_context.wrap_socket(socket.socket(),
3887 server_hostname=hostname) as s:
3888 with self.assertRaises(ssl.SSLError) as e:
3889 s.connect((HOST, server.port))
3890 self.assertIn("alert", str(e.exception))
3891
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003892 @requires_tls_version('SSLv3')
Christian Heimes698dde12018-02-27 11:54:43 +01003893 def test_min_max_version_sslv3(self):
3894 client_context, server_context, hostname = testing_context()
3895 server_context.minimum_version = ssl.TLSVersion.SSLv3
3896 client_context.minimum_version = ssl.TLSVersion.SSLv3
3897 client_context.maximum_version = ssl.TLSVersion.SSLv3
Christian Heimesf6c6b582021-03-18 23:06:50 +01003898 seclevel_workaround(client_context, server_context)
3899
Christian Heimes698dde12018-02-27 11:54:43 +01003900 with ThreadedEchoServer(context=server_context) as server:
3901 with client_context.wrap_socket(socket.socket(),
3902 server_hostname=hostname) as s:
3903 s.connect((HOST, server.port))
3904 self.assertEqual(s.version(), 'SSLv3')
3905
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003906 def test_default_ecdh_curve(self):
3907 # Issue #21015: elliptic curve-based Diffie Hellman key exchange
3908 # should be enabled by default on SSL contexts.
Christian Heimes2875c602021-04-19 07:27:10 +02003909 client_context, server_context, hostname = testing_context()
Christian Heimescb5b68a2017-09-07 18:07:00 -07003910 # TLSv1.3 defaults to PFS key agreement and no longer has KEA in
3911 # cipher name.
Christian Heimes2875c602021-04-19 07:27:10 +02003912 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003913 # Prior to OpenSSL 1.0.0, ECDH ciphers have to be enabled
3914 # explicitly using the 'ECCdraft' cipher alias. Otherwise,
3915 # our default cipher list should prefer ECDH-based ciphers
3916 # automatically.
Christian Heimes2875c602021-04-19 07:27:10 +02003917 with ThreadedEchoServer(context=server_context) as server:
3918 with client_context.wrap_socket(socket.socket(),
3919 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003920 s.connect((HOST, server.port))
3921 self.assertIn("ECDH", s.cipher()[0])
3922
3923 @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES,
3924 "'tls-unique' channel binding not available")
3925 def test_tls_unique_channel_binding(self):
3926 """Test tls-unique channel binding."""
3927 if support.verbose:
3928 sys.stdout.write("\n")
3929
Christian Heimes05d9fe32018-02-27 08:55:39 +01003930 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01003931
3932 server = ThreadedEchoServer(context=server_context,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003933 chatty=True,
3934 connectionchatty=False)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003935
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003936 with server:
Christian Heimes05d9fe32018-02-27 08:55:39 +01003937 with client_context.wrap_socket(
3938 socket.socket(),
3939 server_hostname=hostname) as s:
3940 s.connect((HOST, server.port))
3941 # get the data
3942 cb_data = s.get_channel_binding("tls-unique")
3943 if support.verbose:
3944 sys.stdout.write(
3945 " got channel binding data: {0!r}\n".format(cb_data))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003946
Christian Heimes05d9fe32018-02-27 08:55:39 +01003947 # check if it is sane
3948 self.assertIsNotNone(cb_data)
Christian Heimes529525f2018-05-23 22:24:45 +02003949 if s.version() == 'TLSv1.3':
3950 self.assertEqual(len(cb_data), 48)
3951 else:
3952 self.assertEqual(len(cb_data), 12) # True for TLSv1
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003953
Christian Heimes05d9fe32018-02-27 08:55:39 +01003954 # and compare with the peers version
3955 s.write(b"CB tls-unique\n")
3956 peer_data_repr = s.read().strip()
3957 self.assertEqual(peer_data_repr,
3958 repr(cb_data).encode("us-ascii"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003959
3960 # now, again
Christian Heimes05d9fe32018-02-27 08:55:39 +01003961 with client_context.wrap_socket(
3962 socket.socket(),
3963 server_hostname=hostname) as s:
3964 s.connect((HOST, server.port))
3965 new_cb_data = s.get_channel_binding("tls-unique")
3966 if support.verbose:
3967 sys.stdout.write(
3968 "got another channel binding data: {0!r}\n".format(
3969 new_cb_data)
3970 )
3971 # is it really unique
3972 self.assertNotEqual(cb_data, new_cb_data)
3973 self.assertIsNotNone(cb_data)
Christian Heimes529525f2018-05-23 22:24:45 +02003974 if s.version() == 'TLSv1.3':
3975 self.assertEqual(len(cb_data), 48)
3976 else:
3977 self.assertEqual(len(cb_data), 12) # True for TLSv1
Christian Heimes05d9fe32018-02-27 08:55:39 +01003978 s.write(b"CB tls-unique\n")
3979 peer_data_repr = s.read().strip()
3980 self.assertEqual(peer_data_repr,
3981 repr(new_cb_data).encode("us-ascii"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003982
3983 def test_compression(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02003984 client_context, server_context, hostname = testing_context()
3985 stats = server_params_test(client_context, server_context,
3986 chatty=True, connectionchatty=True,
3987 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003988 if support.verbose:
3989 sys.stdout.write(" got compression: {!r}\n".format(stats['compression']))
3990 self.assertIn(stats['compression'], { None, 'ZLIB', 'RLE' })
3991
3992 @unittest.skipUnless(hasattr(ssl, 'OP_NO_COMPRESSION'),
3993 "ssl.OP_NO_COMPRESSION needed for this test")
3994 def test_compression_disabled(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02003995 client_context, server_context, hostname = testing_context()
3996 client_context.options |= ssl.OP_NO_COMPRESSION
3997 server_context.options |= ssl.OP_NO_COMPRESSION
3998 stats = server_params_test(client_context, server_context,
3999 chatty=True, connectionchatty=True,
4000 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004001 self.assertIs(stats['compression'], None)
4002
Paul Monsonf3550692019-06-19 13:09:54 -07004003 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004004 def test_dh_params(self):
4005 # Check we can get a connection with ephemeral Diffie-Hellman
Christian Heimesa170fa12017-09-15 20:27:30 +02004006 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004007 # test scenario needs TLS <= 1.2
4008 client_context.options |= ssl.OP_NO_TLSv1_3
Christian Heimesa170fa12017-09-15 20:27:30 +02004009 server_context.load_dh_params(DHFILE)
4010 server_context.set_ciphers("kEDH")
Christian Heimes05d9fe32018-02-27 08:55:39 +01004011 server_context.options |= ssl.OP_NO_TLSv1_3
Christian Heimesa170fa12017-09-15 20:27:30 +02004012 stats = server_params_test(client_context, server_context,
4013 chatty=True, connectionchatty=True,
4014 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004015 cipher = stats["cipher"][0]
4016 parts = cipher.split("-")
4017 if "ADH" not in parts and "EDH" not in parts and "DHE" not in parts:
4018 self.fail("Non-DH cipher: " + cipher[0])
4019
Christian Heimesb7b92252018-02-25 09:49:31 +01004020 def test_ecdh_curve(self):
4021 # server secp384r1, client auto
4022 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004023
Christian Heimesb7b92252018-02-25 09:49:31 +01004024 server_context.set_ecdh_curve("secp384r1")
4025 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
Christian Heimesd37b74f2021-04-19 08:31:29 +02004026 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesb7b92252018-02-25 09:49:31 +01004027 stats = server_params_test(client_context, server_context,
4028 chatty=True, connectionchatty=True,
4029 sni_name=hostname)
4030
4031 # server auto, client secp384r1
4032 client_context, server_context, hostname = testing_context()
4033 client_context.set_ecdh_curve("secp384r1")
4034 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
Christian Heimesd37b74f2021-04-19 08:31:29 +02004035 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesb7b92252018-02-25 09:49:31 +01004036 stats = server_params_test(client_context, server_context,
4037 chatty=True, connectionchatty=True,
4038 sni_name=hostname)
4039
4040 # server / client curve mismatch
4041 client_context, server_context, hostname = testing_context()
4042 client_context.set_ecdh_curve("prime256v1")
4043 server_context.set_ecdh_curve("secp384r1")
4044 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
Christian Heimesd37b74f2021-04-19 08:31:29 +02004045 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
4046 with self.assertRaises(ssl.SSLError):
Christian Heimes39258d32021-04-17 11:36:35 +02004047 server_params_test(client_context, server_context,
4048 chatty=True, connectionchatty=True,
4049 sni_name=hostname)
Christian Heimesb7b92252018-02-25 09:49:31 +01004050
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004051 def test_selected_alpn_protocol(self):
4052 # selected_alpn_protocol() is None unless ALPN is used.
Christian Heimesa170fa12017-09-15 20:27:30 +02004053 client_context, server_context, hostname = testing_context()
4054 stats = server_params_test(client_context, server_context,
4055 chatty=True, connectionchatty=True,
4056 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004057 self.assertIs(stats['client_alpn_protocol'], None)
4058
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004059 def test_selected_alpn_protocol_if_server_uses_alpn(self):
4060 # selected_alpn_protocol() is None unless ALPN is used by the client.
Christian Heimesa170fa12017-09-15 20:27:30 +02004061 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004062 server_context.set_alpn_protocols(['foo', 'bar'])
4063 stats = server_params_test(client_context, server_context,
Christian Heimesa170fa12017-09-15 20:27:30 +02004064 chatty=True, connectionchatty=True,
4065 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004066 self.assertIs(stats['client_alpn_protocol'], None)
4067
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004068 def test_alpn_protocols(self):
4069 server_protocols = ['foo', 'bar', 'milkshake']
4070 protocol_tests = [
4071 (['foo', 'bar'], 'foo'),
4072 (['bar', 'foo'], 'foo'),
4073 (['milkshake'], 'milkshake'),
4074 (['http/3.0', 'http/4.0'], None)
4075 ]
4076 for client_protocols, expected in protocol_tests:
Christian Heimesa170fa12017-09-15 20:27:30 +02004077 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004078 server_context.set_alpn_protocols(server_protocols)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004079 client_context.set_alpn_protocols(client_protocols)
4080
4081 try:
4082 stats = server_params_test(client_context,
4083 server_context,
4084 chatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02004085 connectionchatty=True,
4086 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004087 except ssl.SSLError as e:
4088 stats = e
4089
Christian Heimes39258d32021-04-17 11:36:35 +02004090 msg = "failed trying %s (s) and %s (c).\n" \
4091 "was expecting %s, but got %%s from the %%s" \
4092 % (str(server_protocols), str(client_protocols),
4093 str(expected))
4094 client_result = stats['client_alpn_protocol']
4095 self.assertEqual(client_result, expected,
4096 msg % (client_result, "client"))
4097 server_result = stats['server_alpn_protocols'][-1] \
4098 if len(stats['server_alpn_protocols']) else 'nothing'
4099 self.assertEqual(server_result, expected,
4100 msg % (server_result, "server"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004101
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004102 def test_npn_protocols(self):
Christian Heimes39258d32021-04-17 11:36:35 +02004103 assert not ssl.HAS_NPN
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004104
4105 def sni_contexts(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004106 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004107 server_context.load_cert_chain(SIGNED_CERTFILE)
Christian Heimesa170fa12017-09-15 20:27:30 +02004108 other_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004109 other_context.load_cert_chain(SIGNED_CERTFILE2)
Christian Heimesa170fa12017-09-15 20:27:30 +02004110 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004111 client_context.load_verify_locations(SIGNING_CA)
4112 return server_context, other_context, client_context
4113
4114 def check_common_name(self, stats, name):
4115 cert = stats['peercert']
4116 self.assertIn((('commonName', name),), cert['subject'])
4117
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004118 def test_sni_callback(self):
4119 calls = []
4120 server_context, other_context, client_context = self.sni_contexts()
4121
Christian Heimesa170fa12017-09-15 20:27:30 +02004122 client_context.check_hostname = False
4123
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004124 def servername_cb(ssl_sock, server_name, initial_context):
4125 calls.append((server_name, initial_context))
4126 if server_name is not None:
4127 ssl_sock.context = other_context
4128 server_context.set_servername_callback(servername_cb)
4129
4130 stats = server_params_test(client_context, server_context,
4131 chatty=True,
4132 sni_name='supermessage')
4133 # The hostname was fetched properly, and the certificate was
4134 # changed for the connection.
4135 self.assertEqual(calls, [("supermessage", server_context)])
4136 # CERTFILE4 was selected
4137 self.check_common_name(stats, 'fakehostname')
4138
4139 calls = []
4140 # The callback is called with server_name=None
4141 stats = server_params_test(client_context, server_context,
4142 chatty=True,
4143 sni_name=None)
4144 self.assertEqual(calls, [(None, server_context)])
Christian Heimesa170fa12017-09-15 20:27:30 +02004145 self.check_common_name(stats, SIGNED_CERTFILE_HOSTNAME)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004146
4147 # Check disabling the callback
4148 calls = []
4149 server_context.set_servername_callback(None)
4150
4151 stats = server_params_test(client_context, server_context,
4152 chatty=True,
4153 sni_name='notfunny')
4154 # Certificate didn't change
Christian Heimesa170fa12017-09-15 20:27:30 +02004155 self.check_common_name(stats, SIGNED_CERTFILE_HOSTNAME)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004156 self.assertEqual(calls, [])
4157
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004158 def test_sni_callback_alert(self):
4159 # Returning a TLS alert is reflected to the connecting client
4160 server_context, other_context, client_context = self.sni_contexts()
4161
4162 def cb_returning_alert(ssl_sock, server_name, initial_context):
4163 return ssl.ALERT_DESCRIPTION_ACCESS_DENIED
4164 server_context.set_servername_callback(cb_returning_alert)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004165 with self.assertRaises(ssl.SSLError) as cm:
4166 stats = server_params_test(client_context, server_context,
4167 chatty=False,
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004168 sni_name='supermessage')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004169 self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_ACCESS_DENIED')
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004170
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004171 def test_sni_callback_raising(self):
4172 # Raising fails the connection with a TLS handshake failure alert.
4173 server_context, other_context, client_context = self.sni_contexts()
4174
4175 def cb_raising(ssl_sock, server_name, initial_context):
4176 1/0
4177 server_context.set_servername_callback(cb_raising)
4178
Victor Stinner00253502019-06-03 03:51:43 +02004179 with support.catch_unraisable_exception() as catch:
4180 with self.assertRaises(ssl.SSLError) as cm:
4181 stats = server_params_test(client_context, server_context,
4182 chatty=False,
4183 sni_name='supermessage')
4184
4185 self.assertEqual(cm.exception.reason,
4186 'SSLV3_ALERT_HANDSHAKE_FAILURE')
4187 self.assertEqual(catch.unraisable.exc_type, ZeroDivisionError)
Antoine Pitrou50b24d02013-04-11 20:48:42 +02004188
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004189 def test_sni_callback_wrong_return_type(self):
4190 # Returning the wrong return type terminates the TLS connection
4191 # with an internal error alert.
4192 server_context, other_context, client_context = self.sni_contexts()
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004193
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004194 def cb_wrong_return_type(ssl_sock, server_name, initial_context):
4195 return "foo"
4196 server_context.set_servername_callback(cb_wrong_return_type)
4197
Victor Stinner00253502019-06-03 03:51:43 +02004198 with support.catch_unraisable_exception() as catch:
4199 with self.assertRaises(ssl.SSLError) as cm:
4200 stats = server_params_test(client_context, server_context,
4201 chatty=False,
4202 sni_name='supermessage')
4203
4204
4205 self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_INTERNAL_ERROR')
4206 self.assertEqual(catch.unraisable.exc_type, TypeError)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004207
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004208 def test_shared_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004209 client_context, server_context, hostname = testing_context()
Christian Heimese8eb6cb2018-05-22 22:50:12 +02004210 client_context.set_ciphers("AES128:AES256")
4211 server_context.set_ciphers("AES256")
4212 expected_algs = [
4213 "AES256", "AES-256",
4214 # TLS 1.3 ciphers are always enabled
4215 "TLS_CHACHA20", "TLS_AES",
4216 ]
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004217
Christian Heimesa170fa12017-09-15 20:27:30 +02004218 stats = server_params_test(client_context, server_context,
4219 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004220 ciphers = stats['server_shared_ciphers'][0]
4221 self.assertGreater(len(ciphers), 0)
4222 for name, tls_version, bits in ciphers:
Christian Heimese8eb6cb2018-05-22 22:50:12 +02004223 if not any(alg in name for alg in expected_algs):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004224 self.fail(name)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004225
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004226 def test_read_write_after_close_raises_valuerror(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004227 client_context, server_context, hostname = testing_context()
4228 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004229
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004230 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02004231 s = client_context.wrap_socket(socket.socket(),
4232 server_hostname=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004233 s.connect((HOST, server.port))
4234 s.close()
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004235
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004236 self.assertRaises(ValueError, s.read, 1024)
4237 self.assertRaises(ValueError, s.write, b'hello')
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004238
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004239 def test_sendfile(self):
4240 TEST_DATA = b"x" * 512
Hai Shia7f5d932020-08-04 00:41:24 +08004241 with open(os_helper.TESTFN, 'wb') as f:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004242 f.write(TEST_DATA)
Hai Shia7f5d932020-08-04 00:41:24 +08004243 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimes2875c602021-04-19 07:27:10 +02004244 client_context, server_context, hostname = testing_context()
4245 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004246 with server:
Christian Heimes2875c602021-04-19 07:27:10 +02004247 with client_context.wrap_socket(socket.socket(),
4248 server_hostname=hostname) as s:
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004249 s.connect((HOST, server.port))
Hai Shia7f5d932020-08-04 00:41:24 +08004250 with open(os_helper.TESTFN, 'rb') as file:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004251 s.sendfile(file)
4252 self.assertEqual(s.recv(1024), TEST_DATA)
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004253
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004254 def test_session(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004255 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004256 # TODO: sessions aren't compatible with TLSv1.3 yet
4257 client_context.options |= ssl.OP_NO_TLSv1_3
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004258
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004259 # first connection without session
Christian Heimesa170fa12017-09-15 20:27:30 +02004260 stats = server_params_test(client_context, server_context,
4261 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004262 session = stats['session']
4263 self.assertTrue(session.id)
4264 self.assertGreater(session.time, 0)
4265 self.assertGreater(session.timeout, 0)
4266 self.assertTrue(session.has_ticket)
Christian Heimes39258d32021-04-17 11:36:35 +02004267 self.assertGreater(session.ticket_lifetime_hint, 0)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004268 self.assertFalse(stats['session_reused'])
4269 sess_stat = server_context.session_stats()
4270 self.assertEqual(sess_stat['accept'], 1)
4271 self.assertEqual(sess_stat['hits'], 0)
Giampaolo Rodola'915d1412014-06-11 03:54:30 +02004272
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004273 # reuse session
Christian Heimesa170fa12017-09-15 20:27:30 +02004274 stats = server_params_test(client_context, server_context,
4275 session=session, sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004276 sess_stat = server_context.session_stats()
4277 self.assertEqual(sess_stat['accept'], 2)
4278 self.assertEqual(sess_stat['hits'], 1)
4279 self.assertTrue(stats['session_reused'])
4280 session2 = stats['session']
4281 self.assertEqual(session2.id, session.id)
4282 self.assertEqual(session2, session)
4283 self.assertIsNot(session2, session)
4284 self.assertGreaterEqual(session2.time, session.time)
4285 self.assertGreaterEqual(session2.timeout, session.timeout)
Christian Heimes99a65702016-09-10 23:44:53 +02004286
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004287 # another one without session
Christian Heimesa170fa12017-09-15 20:27:30 +02004288 stats = server_params_test(client_context, server_context,
4289 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004290 self.assertFalse(stats['session_reused'])
4291 session3 = stats['session']
4292 self.assertNotEqual(session3.id, session.id)
4293 self.assertNotEqual(session3, session)
4294 sess_stat = server_context.session_stats()
4295 self.assertEqual(sess_stat['accept'], 3)
4296 self.assertEqual(sess_stat['hits'], 1)
Christian Heimes99a65702016-09-10 23:44:53 +02004297
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004298 # reuse session again
Christian Heimesa170fa12017-09-15 20:27:30 +02004299 stats = server_params_test(client_context, server_context,
4300 session=session, sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004301 self.assertTrue(stats['session_reused'])
4302 session4 = stats['session']
4303 self.assertEqual(session4.id, session.id)
4304 self.assertEqual(session4, session)
4305 self.assertGreaterEqual(session4.time, session.time)
4306 self.assertGreaterEqual(session4.timeout, session.timeout)
4307 sess_stat = server_context.session_stats()
4308 self.assertEqual(sess_stat['accept'], 4)
4309 self.assertEqual(sess_stat['hits'], 2)
Christian Heimes99a65702016-09-10 23:44:53 +02004310
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004311 def test_session_handling(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004312 client_context, server_context, hostname = testing_context()
4313 client_context2, _, _ = testing_context()
Christian Heimes99a65702016-09-10 23:44:53 +02004314
Christian Heimes05d9fe32018-02-27 08:55:39 +01004315 # TODO: session reuse does not work with TLSv1.3
Christian Heimesa170fa12017-09-15 20:27:30 +02004316 client_context.options |= ssl.OP_NO_TLSv1_3
4317 client_context2.options |= ssl.OP_NO_TLSv1_3
Christian Heimescb5b68a2017-09-07 18:07:00 -07004318
Christian Heimesa170fa12017-09-15 20:27:30 +02004319 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004320 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02004321 with client_context.wrap_socket(socket.socket(),
4322 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004323 # session is None before handshake
4324 self.assertEqual(s.session, None)
4325 self.assertEqual(s.session_reused, None)
4326 s.connect((HOST, server.port))
4327 session = s.session
4328 self.assertTrue(session)
4329 with self.assertRaises(TypeError) as e:
4330 s.session = object
Ned Deily4531ec72018-06-11 20:26:28 -04004331 self.assertEqual(str(e.exception), 'Value is not a SSLSession.')
Christian Heimes99a65702016-09-10 23:44:53 +02004332
Christian Heimesa170fa12017-09-15 20:27:30 +02004333 with client_context.wrap_socket(socket.socket(),
4334 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004335 s.connect((HOST, server.port))
4336 # cannot set session after handshake
4337 with self.assertRaises(ValueError) as e:
4338 s.session = session
4339 self.assertEqual(str(e.exception),
4340 'Cannot set session after handshake.')
Christian Heimes99a65702016-09-10 23:44:53 +02004341
Christian Heimesa170fa12017-09-15 20:27:30 +02004342 with client_context.wrap_socket(socket.socket(),
4343 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004344 # can set session before handshake and before the
4345 # connection was established
4346 s.session = session
4347 s.connect((HOST, server.port))
4348 self.assertEqual(s.session.id, session.id)
4349 self.assertEqual(s.session, session)
4350 self.assertEqual(s.session_reused, True)
Christian Heimes99a65702016-09-10 23:44:53 +02004351
Christian Heimesa170fa12017-09-15 20:27:30 +02004352 with client_context2.wrap_socket(socket.socket(),
4353 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004354 # cannot re-use session with a different SSLContext
4355 with self.assertRaises(ValueError) as e:
Christian Heimes99a65702016-09-10 23:44:53 +02004356 s.session = session
4357 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004358 self.assertEqual(str(e.exception),
4359 'Session refers to a different SSLContext.')
Christian Heimes99a65702016-09-10 23:44:53 +02004360
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01004361
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02004362@unittest.skipUnless(has_tls_version('TLSv1_3'), "Test needs TLS 1.3")
Christian Heimes9fb051f2018-09-23 08:32:31 +02004363class TestPostHandshakeAuth(unittest.TestCase):
4364 def test_pha_setter(self):
4365 protocols = [
Christian Heimes2875c602021-04-19 07:27:10 +02004366 ssl.PROTOCOL_TLS_SERVER, ssl.PROTOCOL_TLS_CLIENT
Christian Heimes9fb051f2018-09-23 08:32:31 +02004367 ]
4368 for protocol in protocols:
4369 ctx = ssl.SSLContext(protocol)
4370 self.assertEqual(ctx.post_handshake_auth, False)
4371
4372 ctx.post_handshake_auth = True
4373 self.assertEqual(ctx.post_handshake_auth, True)
4374
4375 ctx.verify_mode = ssl.CERT_REQUIRED
4376 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
4377 self.assertEqual(ctx.post_handshake_auth, True)
4378
4379 ctx.post_handshake_auth = False
4380 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
4381 self.assertEqual(ctx.post_handshake_auth, False)
4382
4383 ctx.verify_mode = ssl.CERT_OPTIONAL
4384 ctx.post_handshake_auth = True
4385 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
4386 self.assertEqual(ctx.post_handshake_auth, True)
4387
4388 def test_pha_required(self):
4389 client_context, server_context, hostname = testing_context()
4390 server_context.post_handshake_auth = True
4391 server_context.verify_mode = ssl.CERT_REQUIRED
4392 client_context.post_handshake_auth = True
4393 client_context.load_cert_chain(SIGNED_CERTFILE)
4394
4395 server = ThreadedEchoServer(context=server_context, chatty=False)
4396 with server:
4397 with client_context.wrap_socket(socket.socket(),
4398 server_hostname=hostname) as s:
4399 s.connect((HOST, server.port))
4400 s.write(b'HASCERT')
4401 self.assertEqual(s.recv(1024), b'FALSE\n')
4402 s.write(b'PHA')
4403 self.assertEqual(s.recv(1024), b'OK\n')
4404 s.write(b'HASCERT')
4405 self.assertEqual(s.recv(1024), b'TRUE\n')
4406 # PHA method just returns true when cert is already available
4407 s.write(b'PHA')
4408 self.assertEqual(s.recv(1024), b'OK\n')
4409 s.write(b'GETCERT')
4410 cert_text = s.recv(4096).decode('us-ascii')
4411 self.assertIn('Python Software Foundation CA', cert_text)
4412
4413 def test_pha_required_nocert(self):
4414 client_context, server_context, hostname = testing_context()
4415 server_context.post_handshake_auth = True
4416 server_context.verify_mode = ssl.CERT_REQUIRED
4417 client_context.post_handshake_auth = True
4418
Victor Stinner73ea5462019-07-09 14:33:49 +02004419 # Ignore expected SSLError in ConnectionHandler of ThreadedEchoServer
4420 # (it is only raised sometimes on Windows)
Hai Shie80697d2020-05-28 06:10:27 +08004421 with threading_helper.catch_threading_exception() as cm:
Victor Stinner73ea5462019-07-09 14:33:49 +02004422 server = ThreadedEchoServer(context=server_context, chatty=False)
4423 with server:
4424 with client_context.wrap_socket(socket.socket(),
4425 server_hostname=hostname) as s:
4426 s.connect((HOST, server.port))
4427 s.write(b'PHA')
4428 # receive CertificateRequest
4429 self.assertEqual(s.recv(1024), b'OK\n')
4430 # send empty Certificate + Finish
4431 s.write(b'HASCERT')
4432 # receive alert
4433 with self.assertRaisesRegex(
4434 ssl.SSLError,
4435 'tlsv13 alert certificate required'):
4436 s.recv(1024)
Christian Heimes9fb051f2018-09-23 08:32:31 +02004437
4438 def test_pha_optional(self):
4439 if support.verbose:
4440 sys.stdout.write("\n")
4441
4442 client_context, server_context, hostname = testing_context()
4443 server_context.post_handshake_auth = True
4444 server_context.verify_mode = ssl.CERT_REQUIRED
4445 client_context.post_handshake_auth = True
4446 client_context.load_cert_chain(SIGNED_CERTFILE)
4447
4448 # check CERT_OPTIONAL
4449 server_context.verify_mode = ssl.CERT_OPTIONAL
4450 server = ThreadedEchoServer(context=server_context, chatty=False)
4451 with server:
4452 with client_context.wrap_socket(socket.socket(),
4453 server_hostname=hostname) as s:
4454 s.connect((HOST, server.port))
4455 s.write(b'HASCERT')
4456 self.assertEqual(s.recv(1024), b'FALSE\n')
4457 s.write(b'PHA')
4458 self.assertEqual(s.recv(1024), b'OK\n')
4459 s.write(b'HASCERT')
4460 self.assertEqual(s.recv(1024), b'TRUE\n')
4461
4462 def test_pha_optional_nocert(self):
4463 if support.verbose:
4464 sys.stdout.write("\n")
4465
4466 client_context, server_context, hostname = testing_context()
4467 server_context.post_handshake_auth = True
4468 server_context.verify_mode = ssl.CERT_OPTIONAL
4469 client_context.post_handshake_auth = True
4470
4471 server = ThreadedEchoServer(context=server_context, chatty=False)
4472 with server:
4473 with client_context.wrap_socket(socket.socket(),
4474 server_hostname=hostname) as s:
4475 s.connect((HOST, server.port))
4476 s.write(b'HASCERT')
4477 self.assertEqual(s.recv(1024), b'FALSE\n')
4478 s.write(b'PHA')
4479 self.assertEqual(s.recv(1024), b'OK\n')
penguindustin96466302019-05-06 14:57:17 -04004480 # optional doesn't fail when client does not have a cert
Christian Heimes9fb051f2018-09-23 08:32:31 +02004481 s.write(b'HASCERT')
4482 self.assertEqual(s.recv(1024), b'FALSE\n')
4483
4484 def test_pha_no_pha_client(self):
4485 client_context, server_context, hostname = testing_context()
4486 server_context.post_handshake_auth = True
4487 server_context.verify_mode = ssl.CERT_REQUIRED
4488 client_context.load_cert_chain(SIGNED_CERTFILE)
4489
4490 server = ThreadedEchoServer(context=server_context, chatty=False)
4491 with server:
4492 with client_context.wrap_socket(socket.socket(),
4493 server_hostname=hostname) as s:
4494 s.connect((HOST, server.port))
4495 with self.assertRaisesRegex(ssl.SSLError, 'not server'):
4496 s.verify_client_post_handshake()
4497 s.write(b'PHA')
4498 self.assertIn(b'extension not received', s.recv(1024))
4499
4500 def test_pha_no_pha_server(self):
4501 # server doesn't have PHA enabled, cert is requested in handshake
4502 client_context, server_context, hostname = testing_context()
4503 server_context.verify_mode = ssl.CERT_REQUIRED
4504 client_context.post_handshake_auth = True
4505 client_context.load_cert_chain(SIGNED_CERTFILE)
4506
4507 server = ThreadedEchoServer(context=server_context, chatty=False)
4508 with server:
4509 with client_context.wrap_socket(socket.socket(),
4510 server_hostname=hostname) as s:
4511 s.connect((HOST, server.port))
4512 s.write(b'HASCERT')
4513 self.assertEqual(s.recv(1024), b'TRUE\n')
4514 # PHA doesn't fail if there is already a cert
4515 s.write(b'PHA')
4516 self.assertEqual(s.recv(1024), b'OK\n')
4517 s.write(b'HASCERT')
4518 self.assertEqual(s.recv(1024), b'TRUE\n')
4519
4520 def test_pha_not_tls13(self):
4521 # TLS 1.2
4522 client_context, server_context, hostname = testing_context()
4523 server_context.verify_mode = ssl.CERT_REQUIRED
4524 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
4525 client_context.post_handshake_auth = True
4526 client_context.load_cert_chain(SIGNED_CERTFILE)
4527
4528 server = ThreadedEchoServer(context=server_context, chatty=False)
4529 with server:
4530 with client_context.wrap_socket(socket.socket(),
4531 server_hostname=hostname) as s:
4532 s.connect((HOST, server.port))
4533 # PHA fails for TLS != 1.3
4534 s.write(b'PHA')
4535 self.assertIn(b'WRONG_SSL_VERSION', s.recv(1024))
4536
Christian Heimesf0f59302019-07-01 08:29:17 +02004537 def test_bpo37428_pha_cert_none(self):
4538 # verify that post_handshake_auth does not implicitly enable cert
4539 # validation.
4540 hostname = SIGNED_CERTFILE_HOSTNAME
4541 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4542 client_context.post_handshake_auth = True
4543 client_context.load_cert_chain(SIGNED_CERTFILE)
4544 # no cert validation and CA on client side
4545 client_context.check_hostname = False
4546 client_context.verify_mode = ssl.CERT_NONE
4547
4548 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
4549 server_context.load_cert_chain(SIGNED_CERTFILE)
4550 server_context.load_verify_locations(SIGNING_CA)
4551 server_context.post_handshake_auth = True
4552 server_context.verify_mode = ssl.CERT_REQUIRED
4553
4554 server = ThreadedEchoServer(context=server_context, chatty=False)
4555 with server:
4556 with client_context.wrap_socket(socket.socket(),
4557 server_hostname=hostname) as s:
4558 s.connect((HOST, server.port))
4559 s.write(b'HASCERT')
4560 self.assertEqual(s.recv(1024), b'FALSE\n')
4561 s.write(b'PHA')
4562 self.assertEqual(s.recv(1024), b'OK\n')
4563 s.write(b'HASCERT')
4564 self.assertEqual(s.recv(1024), b'TRUE\n')
4565 # server cert has not been validated
4566 self.assertEqual(s.getpeercert(), {})
4567
Christian Heimes9fb051f2018-09-23 08:32:31 +02004568
Christian Heimesc7f70692019-05-31 11:44:05 +02004569HAS_KEYLOG = hasattr(ssl.SSLContext, 'keylog_filename')
4570requires_keylog = unittest.skipUnless(
4571 HAS_KEYLOG, 'test requires OpenSSL 1.1.1 with keylog callback')
4572
4573class TestSSLDebug(unittest.TestCase):
4574
Hai Shia7f5d932020-08-04 00:41:24 +08004575 def keylog_lines(self, fname=os_helper.TESTFN):
Christian Heimesc7f70692019-05-31 11:44:05 +02004576 with open(fname) as f:
4577 return len(list(f))
4578
4579 @requires_keylog
Paul Monsonf3550692019-06-19 13:09:54 -07004580 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004581 def test_keylog_defaults(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004582 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004583 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4584 self.assertEqual(ctx.keylog_filename, None)
4585
Hai Shia7f5d932020-08-04 00:41:24 +08004586 self.assertFalse(os.path.isfile(os_helper.TESTFN))
4587 ctx.keylog_filename = os_helper.TESTFN
4588 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
4589 self.assertTrue(os.path.isfile(os_helper.TESTFN))
Christian Heimesc7f70692019-05-31 11:44:05 +02004590 self.assertEqual(self.keylog_lines(), 1)
4591
4592 ctx.keylog_filename = None
4593 self.assertEqual(ctx.keylog_filename, None)
4594
4595 with self.assertRaises((IsADirectoryError, PermissionError)):
4596 # Windows raises PermissionError
4597 ctx.keylog_filename = os.path.dirname(
Hai Shia7f5d932020-08-04 00:41:24 +08004598 os.path.abspath(os_helper.TESTFN))
Christian Heimesc7f70692019-05-31 11:44:05 +02004599
4600 with self.assertRaises(TypeError):
4601 ctx.keylog_filename = 1
4602
4603 @requires_keylog
Paul Monsonf3550692019-06-19 13:09:54 -07004604 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004605 def test_keylog_filename(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004606 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004607 client_context, server_context, hostname = testing_context()
4608
Hai Shia7f5d932020-08-04 00:41:24 +08004609 client_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004610 server = ThreadedEchoServer(context=server_context, chatty=False)
4611 with server:
4612 with client_context.wrap_socket(socket.socket(),
4613 server_hostname=hostname) as s:
4614 s.connect((HOST, server.port))
4615 # header, 5 lines for TLS 1.3
4616 self.assertEqual(self.keylog_lines(), 6)
4617
4618 client_context.keylog_filename = None
Hai Shia7f5d932020-08-04 00:41:24 +08004619 server_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004620 server = ThreadedEchoServer(context=server_context, chatty=False)
4621 with server:
4622 with client_context.wrap_socket(socket.socket(),
4623 server_hostname=hostname) as s:
4624 s.connect((HOST, server.port))
4625 self.assertGreaterEqual(self.keylog_lines(), 11)
4626
Hai Shia7f5d932020-08-04 00:41:24 +08004627 client_context.keylog_filename = os_helper.TESTFN
4628 server_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004629 server = ThreadedEchoServer(context=server_context, chatty=False)
4630 with server:
4631 with client_context.wrap_socket(socket.socket(),
4632 server_hostname=hostname) as s:
4633 s.connect((HOST, server.port))
4634 self.assertGreaterEqual(self.keylog_lines(), 21)
4635
4636 client_context.keylog_filename = None
4637 server_context.keylog_filename = None
4638
4639 @requires_keylog
4640 @unittest.skipIf(sys.flags.ignore_environment,
4641 "test is not compatible with ignore_environment")
Paul Monsonf3550692019-06-19 13:09:54 -07004642 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004643 def test_keylog_env(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004644 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004645 with unittest.mock.patch.dict(os.environ):
Hai Shia7f5d932020-08-04 00:41:24 +08004646 os.environ['SSLKEYLOGFILE'] = os_helper.TESTFN
4647 self.assertEqual(os.environ['SSLKEYLOGFILE'], os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004648
4649 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4650 self.assertEqual(ctx.keylog_filename, None)
4651
4652 ctx = ssl.create_default_context()
Hai Shia7f5d932020-08-04 00:41:24 +08004653 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004654
4655 ctx = ssl._create_stdlib_context()
Hai Shia7f5d932020-08-04 00:41:24 +08004656 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004657
4658 def test_msg_callback(self):
4659 client_context, server_context, hostname = testing_context()
4660
4661 def msg_cb(conn, direction, version, content_type, msg_type, data):
4662 pass
4663
4664 self.assertIs(client_context._msg_callback, None)
4665 client_context._msg_callback = msg_cb
4666 self.assertIs(client_context._msg_callback, msg_cb)
4667 with self.assertRaises(TypeError):
4668 client_context._msg_callback = object()
4669
4670 def test_msg_callback_tls12(self):
4671 client_context, server_context, hostname = testing_context()
4672 client_context.options |= ssl.OP_NO_TLSv1_3
4673
4674 msg = []
4675
4676 def msg_cb(conn, direction, version, content_type, msg_type, data):
4677 self.assertIsInstance(conn, ssl.SSLSocket)
4678 self.assertIsInstance(data, bytes)
4679 self.assertIn(direction, {'read', 'write'})
4680 msg.append((direction, version, content_type, msg_type))
4681
4682 client_context._msg_callback = msg_cb
4683
4684 server = ThreadedEchoServer(context=server_context, chatty=False)
4685 with server:
4686 with client_context.wrap_socket(socket.socket(),
4687 server_hostname=hostname) as s:
4688 s.connect((HOST, server.port))
4689
Christian Heimese35d1ba2019-06-03 20:40:15 +02004690 self.assertIn(
Christian Heimesc7f70692019-05-31 11:44:05 +02004691 ("read", TLSVersion.TLSv1_2, _TLSContentType.HANDSHAKE,
4692 _TLSMessageType.SERVER_KEY_EXCHANGE),
Christian Heimese35d1ba2019-06-03 20:40:15 +02004693 msg
4694 )
4695 self.assertIn(
Christian Heimesc7f70692019-05-31 11:44:05 +02004696 ("write", TLSVersion.TLSv1_2, _TLSContentType.CHANGE_CIPHER_SPEC,
4697 _TLSMessageType.CHANGE_CIPHER_SPEC),
Christian Heimese35d1ba2019-06-03 20:40:15 +02004698 msg
4699 )
Christian Heimesc7f70692019-05-31 11:44:05 +02004700
Christian Heimes77cde502021-03-21 16:13:09 +01004701 def test_msg_callback_deadlock_bpo43577(self):
4702 client_context, server_context, hostname = testing_context()
4703 server_context2 = testing_context()[1]
4704
4705 def msg_cb(conn, direction, version, content_type, msg_type, data):
4706 pass
4707
4708 def sni_cb(sock, servername, ctx):
4709 sock.context = server_context2
4710
4711 server_context._msg_callback = msg_cb
4712 server_context.sni_callback = sni_cb
4713
4714 server = ThreadedEchoServer(context=server_context, chatty=False)
4715 with server:
4716 with client_context.wrap_socket(socket.socket(),
4717 server_hostname=hostname) as s:
4718 s.connect((HOST, server.port))
4719 with client_context.wrap_socket(socket.socket(),
4720 server_hostname=hostname) as s:
4721 s.connect((HOST, server.port))
4722
Christian Heimesc7f70692019-05-31 11:44:05 +02004723
Ethan Furmana02cb472021-04-21 10:20:44 -07004724class TestEnumerations(unittest.TestCase):
4725
4726 def test_tlsversion(self):
4727 class CheckedTLSVersion(enum.IntEnum):
4728 MINIMUM_SUPPORTED = _ssl.PROTO_MINIMUM_SUPPORTED
4729 SSLv3 = _ssl.PROTO_SSLv3
4730 TLSv1 = _ssl.PROTO_TLSv1
4731 TLSv1_1 = _ssl.PROTO_TLSv1_1
4732 TLSv1_2 = _ssl.PROTO_TLSv1_2
4733 TLSv1_3 = _ssl.PROTO_TLSv1_3
4734 MAXIMUM_SUPPORTED = _ssl.PROTO_MAXIMUM_SUPPORTED
4735 enum._test_simple_enum(CheckedTLSVersion, TLSVersion)
4736
4737 def test_tlscontenttype(self):
4738 class Checked_TLSContentType(enum.IntEnum):
4739 """Content types (record layer)
4740
4741 See RFC 8446, section B.1
4742 """
4743 CHANGE_CIPHER_SPEC = 20
4744 ALERT = 21
4745 HANDSHAKE = 22
4746 APPLICATION_DATA = 23
4747 # pseudo content types
4748 HEADER = 0x100
4749 INNER_CONTENT_TYPE = 0x101
4750 enum._test_simple_enum(Checked_TLSContentType, _TLSContentType)
4751
4752 def test_tlsalerttype(self):
4753 class Checked_TLSAlertType(enum.IntEnum):
4754 """Alert types for TLSContentType.ALERT messages
4755
4756 See RFC 8466, section B.2
4757 """
4758 CLOSE_NOTIFY = 0
4759 UNEXPECTED_MESSAGE = 10
4760 BAD_RECORD_MAC = 20
4761 DECRYPTION_FAILED = 21
4762 RECORD_OVERFLOW = 22
4763 DECOMPRESSION_FAILURE = 30
4764 HANDSHAKE_FAILURE = 40
4765 NO_CERTIFICATE = 41
4766 BAD_CERTIFICATE = 42
4767 UNSUPPORTED_CERTIFICATE = 43
4768 CERTIFICATE_REVOKED = 44
4769 CERTIFICATE_EXPIRED = 45
4770 CERTIFICATE_UNKNOWN = 46
4771 ILLEGAL_PARAMETER = 47
4772 UNKNOWN_CA = 48
4773 ACCESS_DENIED = 49
4774 DECODE_ERROR = 50
4775 DECRYPT_ERROR = 51
4776 EXPORT_RESTRICTION = 60
4777 PROTOCOL_VERSION = 70
4778 INSUFFICIENT_SECURITY = 71
4779 INTERNAL_ERROR = 80
4780 INAPPROPRIATE_FALLBACK = 86
4781 USER_CANCELED = 90
4782 NO_RENEGOTIATION = 100
4783 MISSING_EXTENSION = 109
4784 UNSUPPORTED_EXTENSION = 110
4785 CERTIFICATE_UNOBTAINABLE = 111
4786 UNRECOGNIZED_NAME = 112
4787 BAD_CERTIFICATE_STATUS_RESPONSE = 113
4788 BAD_CERTIFICATE_HASH_VALUE = 114
4789 UNKNOWN_PSK_IDENTITY = 115
4790 CERTIFICATE_REQUIRED = 116
4791 NO_APPLICATION_PROTOCOL = 120
4792 enum._test_simple_enum(Checked_TLSAlertType, _TLSAlertType)
4793
4794 def test_tlsmessagetype(self):
4795 class Checked_TLSMessageType(enum.IntEnum):
4796 """Message types (handshake protocol)
4797
4798 See RFC 8446, section B.3
4799 """
4800 HELLO_REQUEST = 0
4801 CLIENT_HELLO = 1
4802 SERVER_HELLO = 2
4803 HELLO_VERIFY_REQUEST = 3
4804 NEWSESSION_TICKET = 4
4805 END_OF_EARLY_DATA = 5
4806 HELLO_RETRY_REQUEST = 6
4807 ENCRYPTED_EXTENSIONS = 8
4808 CERTIFICATE = 11
4809 SERVER_KEY_EXCHANGE = 12
4810 CERTIFICATE_REQUEST = 13
4811 SERVER_DONE = 14
4812 CERTIFICATE_VERIFY = 15
4813 CLIENT_KEY_EXCHANGE = 16
4814 FINISHED = 20
4815 CERTIFICATE_URL = 21
4816 CERTIFICATE_STATUS = 22
4817 SUPPLEMENTAL_DATA = 23
4818 KEY_UPDATE = 24
4819 NEXT_PROTO = 67
4820 MESSAGE_HASH = 254
4821 CHANGE_CIPHER_SPEC = 0x0101
4822 enum._test_simple_enum(Checked_TLSMessageType, _TLSMessageType)
4823
4824 def test_sslmethod(self):
4825 Checked_SSLMethod = enum._old_convert_(
4826 enum.IntEnum, '_SSLMethod', 'ssl',
4827 lambda name: name.startswith('PROTOCOL_') and name != 'PROTOCOL_SSLv23',
4828 source=ssl._ssl,
4829 )
4830 enum._test_simple_enum(Checked_SSLMethod, ssl._SSLMethod)
4831
4832 def test_options(self):
4833 CheckedOptions = enum._old_convert_(
4834 enum.FlagEnum, 'Options', 'ssl',
4835 lambda name: name.startswith('OP_'),
4836 source=ssl._ssl,
4837 )
4838 enum._test_simple_enum(CheckedOptions, ssl.Options)
4839
4840
4841 def test_alertdescription(self):
4842 CheckedAlertDescription = enum._old_convert_(
4843 enum.IntEnum, 'AlertDescription', 'ssl',
4844 lambda name: name.startswith('ALERT_DESCRIPTION_'),
4845 source=ssl._ssl,
4846 )
4847 enum._test_simple_enum(CheckedAlertDescription, ssl.AlertDescription)
4848
4849 def test_sslerrornumber(self):
4850 Checked_SSLMethod = enum._old_convert_(
4851 enum.IntEnum, '_SSLMethod', 'ssl',
4852 lambda name: name.startswith('PROTOCOL_') and name != 'PROTOCOL_SSLv23',
4853 source=ssl._ssl,
4854 )
4855 enum._test_simple_enum(Checked_SSLMethod, ssl._SSLMethod)
4856
4857 def test_verifyflags(self):
4858 CheckedVerifyFlags = enum._old_convert_(
4859 enum.FlagEnum, 'VerifyFlags', 'ssl',
4860 lambda name: name.startswith('VERIFY_'),
4861 source=ssl._ssl,
4862 )
4863 enum._test_simple_enum(CheckedVerifyFlags, ssl.VerifyFlags)
4864
4865 def test_verifymode(self):
4866 CheckedVerifyMode = enum._old_convert_(
4867 enum.IntEnum, 'VerifyMode', 'ssl',
4868 lambda name: name.startswith('CERT_'),
4869 source=ssl._ssl,
4870 )
4871 enum._test_simple_enum(CheckedVerifyMode, ssl.VerifyMode)
4872
Thomas Woutersed03b412007-08-28 21:37:11 +00004873def test_main(verbose=False):
Antoine Pitrou15cee622010-08-04 16:45:21 +00004874 if support.verbose:
4875 plats = {
Antoine Pitrou15cee622010-08-04 16:45:21 +00004876 'Mac': platform.mac_ver,
4877 'Windows': platform.win32_ver,
4878 }
Petr Viktorin8b94b412018-05-16 11:51:18 -04004879 for name, func in plats.items():
4880 plat = func()
4881 if plat and plat[0]:
4882 plat = '%s %r' % (name, plat)
4883 break
4884 else:
4885 plat = repr(platform.platform())
Antoine Pitrou15cee622010-08-04 16:45:21 +00004886 print("test_ssl: testing with %r %r" %
4887 (ssl.OPENSSL_VERSION, ssl.OPENSSL_VERSION_INFO))
4888 print(" under %s" % plat)
Antoine Pitroud5323212010-10-22 18:19:07 +00004889 print(" HAS_SNI = %r" % ssl.HAS_SNI)
Antoine Pitrou609ef012013-03-29 18:09:06 +01004890 print(" OP_ALL = 0x%8x" % ssl.OP_ALL)
4891 try:
4892 print(" OP_NO_TLSv1_1 = 0x%8x" % ssl.OP_NO_TLSv1_1)
4893 except AttributeError:
4894 pass
Antoine Pitrou15cee622010-08-04 16:45:21 +00004895
Antoine Pitrou152efa22010-05-16 18:19:27 +00004896 for filename in [
Martin Panter3840b2a2016-03-27 01:53:46 +00004897 CERTFILE, BYTES_CERTFILE,
Antoine Pitrou152efa22010-05-16 18:19:27 +00004898 ONLYCERT, ONLYKEY, BYTES_ONLYCERT, BYTES_ONLYKEY,
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004899 SIGNED_CERTFILE, SIGNED_CERTFILE2, SIGNING_CA,
Antoine Pitrou152efa22010-05-16 18:19:27 +00004900 BADCERT, BADKEY, EMPTYCERT]:
4901 if not os.path.exists(filename):
4902 raise support.TestFailed("Can't read certificate file %r" % filename)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004903
Martin Panter3840b2a2016-03-27 01:53:46 +00004904 tests = [
4905 ContextTests, BasicSocketTests, SSLErrorTests, MemoryBIOTests,
Christian Heimes9d50ab52018-02-27 10:17:30 +01004906 SSLObjectTests, SimpleBackgroundTests, ThreadedTests,
Christian Heimesc7f70692019-05-31 11:44:05 +02004907 TestPostHandshakeAuth, TestSSLDebug
Martin Panter3840b2a2016-03-27 01:53:46 +00004908 ]
Thomas Woutersed03b412007-08-28 21:37:11 +00004909
Benjamin Petersonee8712c2008-05-20 21:35:26 +00004910 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00004911 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00004912
Hai Shie80697d2020-05-28 06:10:27 +08004913 thread_info = threading_helper.threading_setup()
Antoine Pitrou480a1242010-04-28 21:37:09 +00004914 try:
4915 support.run_unittest(*tests)
4916 finally:
Hai Shie80697d2020-05-28 06:10:27 +08004917 threading_helper.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00004918
4919if __name__ == "__main__":
4920 test_main()