blob: 54007c78ed31aecd2f5d44505e7cf799f23a4a34 [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
Christian Heimes9424bb42013-06-17 15:32:57 +020015import datetime
Antoine Pitroucfcd8ad2010-04-23 23:31:47 +000016import gc
Thomas Woutersed03b412007-08-28 21:37:11 +000017import os
Antoine Pitroucfcd8ad2010-04-23 23:31:47 +000018import errno
Thomas Woutersed03b412007-08-28 21:37:11 +000019import pprint
Antoine Pitrou803e6d62010-10-13 10:36:15 +000020import urllib.request
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020021import threading
Thomas Woutersed03b412007-08-28 21:37:11 +000022import traceback
Bill Janssen54cc54c2007-12-14 22:08:56 +000023import asyncore
Antoine Pitrou9d543662010-04-23 23:10:32 +000024import weakref
Antoine Pitrou15cee622010-08-04 16:45:21 +000025import platform
Christian Heimes892d66e2018-01-29 14:10:18 +010026import sysconfig
Christian Heimesdf6ac7e2019-09-26 17:02:59 +020027import functools
Christian Heimes888bbdc2017-09-07 14:18:21 -070028try:
29 import ctypes
30except ImportError:
31 ctypes = None
Thomas Woutersed03b412007-08-28 21:37:11 +000032
Hai Shia7f5d932020-08-04 00:41:24 +080033ssl = import_helper.import_module("ssl")
Antoine Pitrou05d936d2010-10-13 11:38:36 +000034
Victor Stinner8f4ef3b2019-07-01 18:28:25 +020035from ssl import TLSVersion, _TLSContentType, _TLSMessageType
Martin Panter3840b2a2016-03-27 01:53:46 +000036
Paul Monsonf3550692019-06-19 13:09:54 -070037Py_DEBUG = hasattr(sys, 'gettotalrefcount')
38Py_DEBUG_WIN32 = Py_DEBUG and sys.platform == 'win32'
39
Antoine Pitrou2463e5f2013-03-28 22:24:43 +010040PROTOCOLS = sorted(ssl._PROTOCOL_NAMES)
Serhiy Storchaka16994912020-04-25 10:06:29 +030041HOST = socket_helper.HOST
Christian Heimes598894f2016-09-05 23:19:05 +020042IS_LIBRESSL = ssl.OPENSSL_VERSION.startswith('LibreSSL')
Christian Heimes05d9fe32018-02-27 08:55:39 +010043IS_OPENSSL_1_1_0 = not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0)
44IS_OPENSSL_1_1_1 = not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 1)
Christian Heimes5151d642021-04-09 15:43:06 +020045IS_OPENSSL_3_0_0 = not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (3, 0, 0)
Christian Heimes892d66e2018-01-29 14:10:18 +010046PY_SSL_DEFAULT_CIPHERS = sysconfig.get_config_var('PY_SSL_DEFAULT_CIPHERS')
Antoine Pitrou152efa22010-05-16 18:19:27 +000047
Victor Stinner3ef63442019-02-19 18:06:03 +010048PROTOCOL_TO_TLS_VERSION = {}
49for proto, ver in (
50 ("PROTOCOL_SSLv23", "SSLv3"),
51 ("PROTOCOL_TLSv1", "TLSv1"),
52 ("PROTOCOL_TLSv1_1", "TLSv1_1"),
53):
54 try:
55 proto = getattr(ssl, proto)
56 ver = getattr(ssl.TLSVersion, ver)
57 except AttributeError:
58 continue
59 PROTOCOL_TO_TLS_VERSION[proto] = ver
60
Christian Heimesefff7062013-11-21 03:35:02 +010061def data_file(*name):
62 return os.path.join(os.path.dirname(__file__), *name)
Antoine Pitrou152efa22010-05-16 18:19:27 +000063
Antoine Pitrou81564092010-10-08 23:06:24 +000064# The custom key and certificate files used in test_ssl are generated
65# using Lib/test/make_ssl_certs.py.
66# Other certificates are simply fetched from the Internet servers they
67# are meant to authenticate.
68
Antoine Pitrou152efa22010-05-16 18:19:27 +000069CERTFILE = data_file("keycert.pem")
Victor Stinner313a1202010-06-11 23:56:51 +000070BYTES_CERTFILE = os.fsencode(CERTFILE)
Antoine Pitrou152efa22010-05-16 18:19:27 +000071ONLYCERT = data_file("ssl_cert.pem")
72ONLYKEY = data_file("ssl_key.pem")
Victor Stinner313a1202010-06-11 23:56:51 +000073BYTES_ONLYCERT = os.fsencode(ONLYCERT)
74BYTES_ONLYKEY = os.fsencode(ONLYKEY)
Antoine Pitrou4fd1e6a2011-08-25 14:39:44 +020075CERTFILE_PROTECTED = data_file("keycert.passwd.pem")
76ONLYKEY_PROTECTED = data_file("ssl_key.passwd.pem")
77KEY_PASSWORD = "somepass"
Antoine Pitrou152efa22010-05-16 18:19:27 +000078CAPATH = data_file("capath")
Victor Stinner313a1202010-06-11 23:56:51 +000079BYTES_CAPATH = os.fsencode(CAPATH)
Christian Heimesefff7062013-11-21 03:35:02 +010080CAFILE_NEURONIO = data_file("capath", "4e1295a3.0")
81CAFILE_CACERT = data_file("capath", "5ed36f99.0")
82
Christian Heimesbd5c7d22018-01-20 15:16:30 +010083CERTFILE_INFO = {
84 'issuer': ((('countryName', 'XY'),),
85 (('localityName', 'Castle Anthrax'),),
86 (('organizationName', 'Python Software Foundation'),),
87 (('commonName', 'localhost'),)),
Christian Heimese6dac002018-08-30 07:25:49 +020088 'notAfter': 'Aug 26 14:23:15 2028 GMT',
89 'notBefore': 'Aug 29 14:23:15 2018 GMT',
90 'serialNumber': '98A7CF88C74A32ED',
Christian Heimesbd5c7d22018-01-20 15:16:30 +010091 'subject': ((('countryName', 'XY'),),
92 (('localityName', 'Castle Anthrax'),),
93 (('organizationName', 'Python Software Foundation'),),
94 (('commonName', 'localhost'),)),
95 'subjectAltName': (('DNS', 'localhost'),),
96 'version': 3
97}
Antoine Pitrou152efa22010-05-16 18:19:27 +000098
Christian Heimes22587792013-11-21 23:56:13 +010099# empty CRL
100CRLFILE = data_file("revocation.crl")
101
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100102# Two keys and certs signed by the same CA (for SNI tests)
103SIGNED_CERTFILE = data_file("keycert3.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +0200104SIGNED_CERTFILE_HOSTNAME = 'localhost'
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100105
106SIGNED_CERTFILE_INFO = {
107 'OCSP': ('http://testca.pythontest.net/testca/ocsp/',),
108 'caIssuers': ('http://testca.pythontest.net/testca/pycacert.cer',),
109 'crlDistributionPoints': ('http://testca.pythontest.net/testca/revocation.crl',),
110 'issuer': ((('countryName', 'XY'),),
111 (('organizationName', 'Python Software Foundation CA'),),
112 (('commonName', 'our-ca-server'),)),
Christian Heimesb467d9a2021-04-17 10:07:19 +0200113 'notAfter': 'Oct 28 14:23:16 2037 GMT',
Christian Heimese6dac002018-08-30 07:25:49 +0200114 'notBefore': 'Aug 29 14:23:16 2018 GMT',
115 'serialNumber': 'CB2D80995A69525C',
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100116 'subject': ((('countryName', 'XY'),),
117 (('localityName', 'Castle Anthrax'),),
118 (('organizationName', 'Python Software Foundation'),),
119 (('commonName', 'localhost'),)),
120 'subjectAltName': (('DNS', 'localhost'),),
121 'version': 3
122}
123
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100124SIGNED_CERTFILE2 = data_file("keycert4.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +0200125SIGNED_CERTFILE2_HOSTNAME = 'fakehostname'
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100126SIGNED_CERTFILE_ECC = data_file("keycertecc.pem")
127SIGNED_CERTFILE_ECC_HOSTNAME = 'localhost-ecc'
128
Martin Panter3840b2a2016-03-27 01:53:46 +0000129# Same certificate as pycacert.pem, but without extra text in file
130SIGNING_CA = data_file("capath", "ceff1710.0")
Christian Heimes1c03abd2016-09-06 23:25:35 +0200131# cert with all kinds of subject alt names
132ALLSANFILE = data_file("allsans.pem")
Christian Heimes66e57422018-01-29 14:25:13 +0100133IDNSANSFILE = data_file("idnsans.pem")
Christian Heimesb467d9a2021-04-17 10:07:19 +0200134NOSANFILE = data_file("nosan.pem")
135NOSAN_HOSTNAME = 'localhost'
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100136
Martin Panter3d81d932016-01-14 09:36:00 +0000137REMOTE_HOST = "self-signed.pythontest.net"
Antoine Pitrou152efa22010-05-16 18:19:27 +0000138
139EMPTYCERT = data_file("nullcert.pem")
140BADCERT = data_file("badcert.pem")
Martin Panter407b62f2016-01-30 03:41:43 +0000141NONEXISTINGCERT = data_file("XXXnonexisting.pem")
Antoine Pitrou152efa22010-05-16 18:19:27 +0000142BADKEY = data_file("badkey.pem")
Antoine Pitroud8c347a2011-10-01 19:20:25 +0200143NOKIACERT = data_file("nokia.pem")
Christian Heimes824f7f32013-08-17 00:54:47 +0200144NULLBYTECERT = data_file("nullbytecert.pem")
Christian Heimesa37f5242019-01-15 23:47:42 +0100145TALOS_INVALID_CRLDP = data_file("talos-2019-0758.pem")
Antoine Pitrou152efa22010-05-16 18:19:27 +0000146
Christian Heimes88bfd0b2018-08-14 12:54:19 +0200147DHFILE = data_file("ffdh3072.pem")
Antoine Pitrou0e576f12011-12-22 10:03:38 +0100148BYTES_DHFILE = os.fsencode(DHFILE)
Thomas Woutersed03b412007-08-28 21:37:11 +0000149
Christian Heimes358cfd42016-09-10 22:43:48 +0200150# Not defined in all versions of OpenSSL
151OP_NO_COMPRESSION = getattr(ssl, "OP_NO_COMPRESSION", 0)
152OP_SINGLE_DH_USE = getattr(ssl, "OP_SINGLE_DH_USE", 0)
153OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0)
154OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0)
Christian Heimes05d9fe32018-02-27 08:55:39 +0100155OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0)
Christian Heimes6f37ebc2021-04-09 17:59:21 +0200156OP_IGNORE_UNEXPECTED_EOF = getattr(ssl, "OP_IGNORE_UNEXPECTED_EOF", 0)
Christian Heimes358cfd42016-09-10 22:43:48 +0200157
Christian Heimesf6c6b582021-03-18 23:06:50 +0100158# Ubuntu has patched OpenSSL and changed behavior of security level 2
159# see https://bugs.python.org/issue41561#msg389003
160def is_ubuntu():
161 try:
162 # Assume that any references of "ubuntu" implies Ubuntu-like distro
163 # The workaround is not required for 18.04, but doesn't hurt either.
164 with open("/etc/os-release", encoding="utf-8") as f:
165 return "ubuntu" in f.read()
166 except FileNotFoundError:
167 return False
168
169if is_ubuntu():
170 def seclevel_workaround(*ctxs):
171 """"Lower security level to '1' and allow all ciphers for TLS 1.0/1"""
172 for ctx in ctxs:
Christian Heimes34477502021-04-12 12:00:38 +0200173 if (
174 hasattr(ctx, "minimum_version") and
175 ctx.minimum_version <= ssl.TLSVersion.TLSv1_1
176 ):
Christian Heimesf6c6b582021-03-18 23:06:50 +0100177 ctx.set_ciphers("@SECLEVEL=1:ALL")
178else:
179 def seclevel_workaround(*ctxs):
180 pass
181
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100182
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200183def has_tls_protocol(protocol):
184 """Check if a TLS protocol is available and enabled
185
186 :param protocol: enum ssl._SSLMethod member or name
187 :return: bool
188 """
189 if isinstance(protocol, str):
190 assert protocol.startswith('PROTOCOL_')
191 protocol = getattr(ssl, protocol, None)
192 if protocol is None:
193 return False
194 if protocol in {
195 ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS_SERVER,
196 ssl.PROTOCOL_TLS_CLIENT
197 }:
198 # auto-negotiate protocols are always available
199 return True
200 name = protocol.name
201 return has_tls_version(name[len('PROTOCOL_'):])
202
203
204@functools.lru_cache
205def has_tls_version(version):
206 """Check if a TLS/SSL version is enabled
207
208 :param version: TLS version name or ssl.TLSVersion member
209 :return: bool
210 """
211 if version == "SSLv2":
212 # never supported and not even in TLSVersion enum
213 return False
214
215 if isinstance(version, str):
216 version = ssl.TLSVersion.__members__[version]
217
218 # check compile time flags like ssl.HAS_TLSv1_2
219 if not getattr(ssl, f'HAS_{version.name}'):
220 return False
221
Christian Heimes5151d642021-04-09 15:43:06 +0200222 if IS_OPENSSL_3_0_0 and version < ssl.TLSVersion.TLSv1_2:
223 # bpo43791: 3.0.0-alpha14 fails with TLSV1_ALERT_INTERNAL_ERROR
224 return False
225
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200226 # check runtime and dynamic crypto policy settings. A TLS version may
227 # be compiled in but disabled by a policy or config option.
228 ctx = ssl.SSLContext()
229 if (
Christian Heimes9f772682019-09-26 18:23:17 +0200230 hasattr(ctx, 'minimum_version') and
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200231 ctx.minimum_version != ssl.TLSVersion.MINIMUM_SUPPORTED and
232 version < ctx.minimum_version
233 ):
234 return False
235 if (
Christian Heimes9f772682019-09-26 18:23:17 +0200236 hasattr(ctx, 'maximum_version') and
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200237 ctx.maximum_version != ssl.TLSVersion.MAXIMUM_SUPPORTED and
238 version > ctx.maximum_version
239 ):
240 return False
241
242 return True
243
244
245def requires_tls_version(version):
246 """Decorator to skip tests when a required TLS version is not available
247
248 :param version: TLS version name or ssl.TLSVersion member
249 :return:
250 """
251 def decorator(func):
252 @functools.wraps(func)
253 def wrapper(*args, **kw):
254 if not has_tls_version(version):
255 raise unittest.SkipTest(f"{version} is not available.")
256 else:
257 return func(*args, **kw)
258 return wrapper
259 return decorator
260
261
262requires_minimum_version = unittest.skipUnless(
263 hasattr(ssl.SSLContext, 'minimum_version'),
264 "required OpenSSL >= 1.1.0g"
265)
266
267
Thomas Woutersed03b412007-08-28 21:37:11 +0000268def handle_error(prefix):
269 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000270 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000271 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +0000272
Antoine Pitroub5218772010-05-21 09:56:06 +0000273def can_clear_options():
274 # 0.9.8m or higher
Antoine Pitroub9ac25d2011-07-08 18:47:06 +0200275 return ssl._OPENSSL_API_VERSION >= (0, 9, 8, 13, 15)
Antoine Pitroub5218772010-05-21 09:56:06 +0000276
277def no_sslv2_implies_sslv3_hello():
278 # 0.9.7h or higher
279 return ssl.OPENSSL_VERSION_INFO >= (0, 9, 7, 8, 15)
280
Christian Heimes2427b502013-11-23 11:24:32 +0100281def have_verify_flags():
282 # 0.9.8 or higher
283 return ssl.OPENSSL_VERSION_INFO >= (0, 9, 8, 0, 15)
284
Christian Heimesb7b92252018-02-25 09:49:31 +0100285def _have_secp_curves():
286 if not ssl.HAS_ECDH:
287 return False
288 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
289 try:
290 ctx.set_ecdh_curve("secp384r1")
291 except ValueError:
292 return False
293 else:
294 return True
295
296
297HAVE_SECP_CURVES = _have_secp_curves()
298
299
Antoine Pitrouc695c952014-04-28 20:57:36 +0200300def utc_offset(): #NOTE: ignore issues like #1647654
301 # local time = utc time + utc offset
302 if time.daylight and time.localtime().tm_isdst > 0:
303 return -time.altzone # seconds
304 return -time.timezone
305
Christian Heimes9424bb42013-06-17 15:32:57 +0200306def asn1time(cert_time):
307 # Some versions of OpenSSL ignore seconds, see #18207
308 # 0.9.8.i
309 if ssl._OPENSSL_API_VERSION == (0, 9, 8, 9, 15):
310 fmt = "%b %d %H:%M:%S %Y GMT"
311 dt = datetime.datetime.strptime(cert_time, fmt)
312 dt = dt.replace(second=0)
313 cert_time = dt.strftime(fmt)
314 # %d adds leading zero but ASN1_TIME_print() uses leading space
315 if cert_time[4] == "0":
316 cert_time = cert_time[:4] + " " + cert_time[5:]
317
318 return cert_time
Thomas Woutersed03b412007-08-28 21:37:11 +0000319
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100320needs_sni = unittest.skipUnless(ssl.HAS_SNI, "SNI support needed for this test")
321
Antoine Pitrou23df4832010-08-04 17:14:06 +0000322
Christian Heimesd0486372016-09-10 23:23:33 +0200323def test_wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLS, *,
324 cert_reqs=ssl.CERT_NONE, ca_certs=None,
325 ciphers=None, certfile=None, keyfile=None,
326 **kwargs):
327 context = ssl.SSLContext(ssl_version)
328 if cert_reqs is not None:
Christian Heimesa170fa12017-09-15 20:27:30 +0200329 if cert_reqs == ssl.CERT_NONE:
330 context.check_hostname = False
Christian Heimesd0486372016-09-10 23:23:33 +0200331 context.verify_mode = cert_reqs
332 if ca_certs is not None:
333 context.load_verify_locations(ca_certs)
334 if certfile is not None or keyfile is not None:
335 context.load_cert_chain(certfile, keyfile)
336 if ciphers is not None:
337 context.set_ciphers(ciphers)
338 return context.wrap_socket(sock, **kwargs)
339
Christian Heimesa170fa12017-09-15 20:27:30 +0200340
341def testing_context(server_cert=SIGNED_CERTFILE):
342 """Create context
343
344 client_context, server_context, hostname = testing_context()
345 """
346 if server_cert == SIGNED_CERTFILE:
347 hostname = SIGNED_CERTFILE_HOSTNAME
348 elif server_cert == SIGNED_CERTFILE2:
349 hostname = SIGNED_CERTFILE2_HOSTNAME
Christian Heimesb467d9a2021-04-17 10:07:19 +0200350 elif server_cert == NOSANFILE:
351 hostname = NOSAN_HOSTNAME
Christian Heimesa170fa12017-09-15 20:27:30 +0200352 else:
353 raise ValueError(server_cert)
354
355 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
356 client_context.load_verify_locations(SIGNING_CA)
357
358 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
359 server_context.load_cert_chain(server_cert)
Christian Heimes9fb051f2018-09-23 08:32:31 +0200360 server_context.load_verify_locations(SIGNING_CA)
Christian Heimesa170fa12017-09-15 20:27:30 +0200361
362 return client_context, server_context, hostname
363
364
Antoine Pitrou152efa22010-05-16 18:19:27 +0000365class BasicSocketTests(unittest.TestCase):
Thomas Woutersed03b412007-08-28 21:37:11 +0000366
Antoine Pitrou480a1242010-04-28 21:37:09 +0000367 def test_constants(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000368 ssl.CERT_NONE
369 ssl.CERT_OPTIONAL
370 ssl.CERT_REQUIRED
Antoine Pitrou6db49442011-12-19 13:27:11 +0100371 ssl.OP_CIPHER_SERVER_PREFERENCE
Antoine Pitrou0e576f12011-12-22 10:03:38 +0100372 ssl.OP_SINGLE_DH_USE
Antoine Pitrouc135fa42012-02-19 21:22:39 +0100373 if ssl.HAS_ECDH:
374 ssl.OP_SINGLE_ECDH_USE
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +0100375 if ssl.OPENSSL_VERSION_INFO >= (1, 0):
376 ssl.OP_NO_COMPRESSION
Antoine Pitroud5323212010-10-22 18:19:07 +0000377 self.assertIn(ssl.HAS_SNI, {True, False})
Antoine Pitrou501da612011-12-21 09:27:41 +0100378 self.assertIn(ssl.HAS_ECDH, {True, False})
Christian Heimescb5b68a2017-09-07 18:07:00 -0700379 ssl.OP_NO_SSLv2
380 ssl.OP_NO_SSLv3
381 ssl.OP_NO_TLSv1
382 ssl.OP_NO_TLSv1_3
383 if ssl.OPENSSL_VERSION_INFO >= (1, 0, 1):
384 ssl.OP_NO_TLSv1_1
385 ssl.OP_NO_TLSv1_2
Christian Heimesa170fa12017-09-15 20:27:30 +0200386 self.assertEqual(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv23)
Thomas Woutersed03b412007-08-28 21:37:11 +0000387
Christian Heimes9d50ab52018-02-27 10:17:30 +0100388 def test_private_init(self):
389 with self.assertRaisesRegex(TypeError, "public constructor"):
390 with socket.socket() as s:
391 ssl.SSLSocket(s)
392
Antoine Pitrou172f0252014-04-18 20:33:08 +0200393 def test_str_for_enums(self):
394 # Make sure that the PROTOCOL_* constants have enum-like string
395 # reprs.
Christian Heimes598894f2016-09-05 23:19:05 +0200396 proto = ssl.PROTOCOL_TLS
Ethan Furmanb7751062021-03-30 21:17:26 -0700397 self.assertEqual(str(proto), 'PROTOCOL_TLS')
Antoine Pitrou172f0252014-04-18 20:33:08 +0200398 ctx = ssl.SSLContext(proto)
399 self.assertIs(ctx.protocol, proto)
400
Antoine Pitrou480a1242010-04-28 21:37:09 +0000401 def test_random(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000402 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000403 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000404 sys.stdout.write("\n RAND_status is %d (%s)\n"
405 % (v, (v and "sufficient randomness") or
406 "insufficient randomness"))
Victor Stinner99c8b162011-05-24 12:05:19 +0200407
408 data, is_cryptographic = ssl.RAND_pseudo_bytes(16)
409 self.assertEqual(len(data), 16)
410 self.assertEqual(is_cryptographic, v == 1)
411 if v:
412 data = ssl.RAND_bytes(16)
413 self.assertEqual(len(data), 16)
Victor Stinner2e2baa92011-05-25 11:15:16 +0200414 else:
415 self.assertRaises(ssl.SSLError, ssl.RAND_bytes, 16)
Victor Stinner99c8b162011-05-24 12:05:19 +0200416
Victor Stinner1e81a392013-12-19 16:47:04 +0100417 # negative num is invalid
418 self.assertRaises(ValueError, ssl.RAND_bytes, -5)
419 self.assertRaises(ValueError, ssl.RAND_pseudo_bytes, -5)
420
Victor Stinnerbeeb5122014-11-28 13:28:25 +0100421 if hasattr(ssl, 'RAND_egd'):
422 self.assertRaises(TypeError, ssl.RAND_egd, 1)
423 self.assertRaises(TypeError, ssl.RAND_egd, 'foo', 1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000424 ssl.RAND_add("this is a random string", 75.0)
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200425 ssl.RAND_add(b"this is a random bytes object", 75.0)
426 ssl.RAND_add(bytearray(b"this is a random bytearray object"), 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +0000427
pxinwr98a54172020-12-09 07:20:19 +0800428 @unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork')
Christian Heimesf77b4b22013-08-21 13:26:05 +0200429 def test_random_fork(self):
430 status = ssl.RAND_status()
431 if not status:
432 self.fail("OpenSSL's PRNG has insufficient randomness")
433
434 rfd, wfd = os.pipe()
435 pid = os.fork()
436 if pid == 0:
437 try:
438 os.close(rfd)
439 child_random = ssl.RAND_pseudo_bytes(16)[0]
440 self.assertEqual(len(child_random), 16)
441 os.write(wfd, child_random)
442 os.close(wfd)
443 except BaseException:
444 os._exit(1)
445 else:
446 os._exit(0)
447 else:
448 os.close(wfd)
449 self.addCleanup(os.close, rfd)
Victor Stinner278c1e12020-03-31 20:08:12 +0200450 support.wait_process(pid, exitcode=0)
Christian Heimesf77b4b22013-08-21 13:26:05 +0200451
452 child_random = os.read(rfd, 16)
453 self.assertEqual(len(child_random), 16)
454 parent_random = ssl.RAND_pseudo_bytes(16)[0]
455 self.assertEqual(len(parent_random), 16)
456
457 self.assertNotEqual(child_random, parent_random)
458
Christian Heimese6dac002018-08-30 07:25:49 +0200459 maxDiff = None
460
Antoine Pitrou480a1242010-04-28 21:37:09 +0000461 def test_parse_cert(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000462 # note that this uses an 'unofficial' function in _ssl.c,
463 # provided solely for this test, to exercise the certificate
464 # parsing code
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100465 self.assertEqual(
466 ssl._ssl._test_decode_cert(CERTFILE),
467 CERTFILE_INFO
468 )
469 self.assertEqual(
470 ssl._ssl._test_decode_cert(SIGNED_CERTFILE),
471 SIGNED_CERTFILE_INFO
472 )
473
Antoine Pitroud8c347a2011-10-01 19:20:25 +0200474 # Issue #13034: the subjectAltName in some certificates
475 # (notably projects.developer.nokia.com:443) wasn't parsed
476 p = ssl._ssl._test_decode_cert(NOKIACERT)
477 if support.verbose:
478 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
479 self.assertEqual(p['subjectAltName'],
480 (('DNS', 'projects.developer.nokia.com'),
481 ('DNS', 'projects.forum.nokia.com'))
482 )
Christian Heimesbd3a7f92013-11-21 03:40:15 +0100483 # extra OCSP and AIA fields
484 self.assertEqual(p['OCSP'], ('http://ocsp.verisign.com',))
485 self.assertEqual(p['caIssuers'],
486 ('http://SVRIntl-G3-aia.verisign.com/SVRIntlG3.cer',))
487 self.assertEqual(p['crlDistributionPoints'],
488 ('http://SVRIntl-G3-crl.verisign.com/SVRIntlG3.crl',))
Thomas Woutersed03b412007-08-28 21:37:11 +0000489
Christian Heimesa37f5242019-01-15 23:47:42 +0100490 def test_parse_cert_CVE_2019_5010(self):
491 p = ssl._ssl._test_decode_cert(TALOS_INVALID_CRLDP)
492 if support.verbose:
493 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
494 self.assertEqual(
495 p,
496 {
497 'issuer': (
498 (('countryName', 'UK'),), (('commonName', 'cody-ca'),)),
499 'notAfter': 'Jun 14 18:00:58 2028 GMT',
500 'notBefore': 'Jun 18 18:00:58 2018 GMT',
501 'serialNumber': '02',
502 'subject': ((('countryName', 'UK'),),
503 (('commonName',
504 'codenomicon-vm-2.test.lal.cisco.com'),)),
505 'subjectAltName': (
506 ('DNS', 'codenomicon-vm-2.test.lal.cisco.com'),),
507 'version': 3
508 }
509 )
510
Christian Heimes824f7f32013-08-17 00:54:47 +0200511 def test_parse_cert_CVE_2013_4238(self):
512 p = ssl._ssl._test_decode_cert(NULLBYTECERT)
513 if support.verbose:
514 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
515 subject = ((('countryName', 'US'),),
516 (('stateOrProvinceName', 'Oregon'),),
517 (('localityName', 'Beaverton'),),
518 (('organizationName', 'Python Software Foundation'),),
519 (('organizationalUnitName', 'Python Core Development'),),
520 (('commonName', 'null.python.org\x00example.org'),),
521 (('emailAddress', 'python-dev@python.org'),))
522 self.assertEqual(p['subject'], subject)
523 self.assertEqual(p['issuer'], subject)
Christian Heimes157c9832013-08-25 14:12:41 +0200524 if ssl._OPENSSL_API_VERSION >= (0, 9, 8):
525 san = (('DNS', 'altnull.python.org\x00example.com'),
526 ('email', 'null@python.org\x00user@example.org'),
527 ('URI', 'http://null.python.org\x00http://example.org'),
528 ('IP Address', '192.0.2.1'),
Christian Heimes2b7de662019-12-07 17:59:36 +0100529 ('IP Address', '2001:DB8:0:0:0:0:0:1'))
Christian Heimes157c9832013-08-25 14:12:41 +0200530 else:
531 # OpenSSL 0.9.7 doesn't support IPv6 addresses in subjectAltName
532 san = (('DNS', 'altnull.python.org\x00example.com'),
533 ('email', 'null@python.org\x00user@example.org'),
534 ('URI', 'http://null.python.org\x00http://example.org'),
535 ('IP Address', '192.0.2.1'),
536 ('IP Address', '<invalid>'))
537
538 self.assertEqual(p['subjectAltName'], san)
Christian Heimes824f7f32013-08-17 00:54:47 +0200539
Christian Heimes1c03abd2016-09-06 23:25:35 +0200540 def test_parse_all_sans(self):
541 p = ssl._ssl._test_decode_cert(ALLSANFILE)
542 self.assertEqual(p['subjectAltName'],
543 (
544 ('DNS', 'allsans'),
545 ('othername', '<unsupported>'),
546 ('othername', '<unsupported>'),
547 ('email', 'user@example.org'),
548 ('DNS', 'www.example.org'),
549 ('DirName',
550 ((('countryName', 'XY'),),
551 (('localityName', 'Castle Anthrax'),),
552 (('organizationName', 'Python Software Foundation'),),
553 (('commonName', 'dirname example'),))),
554 ('URI', 'https://www.python.org/'),
555 ('IP Address', '127.0.0.1'),
Christian Heimes2b7de662019-12-07 17:59:36 +0100556 ('IP Address', '0:0:0:0:0:0:0:1'),
Christian Heimes1c03abd2016-09-06 23:25:35 +0200557 ('Registered ID', '1.2.3.4.5')
558 )
559 )
560
Antoine Pitrou480a1242010-04-28 21:37:09 +0000561 def test_DER_to_PEM(self):
Martin Panter3d81d932016-01-14 09:36:00 +0000562 with open(CAFILE_CACERT, 'r') as f:
Antoine Pitrou480a1242010-04-28 21:37:09 +0000563 pem = f.read()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000564 d1 = ssl.PEM_cert_to_DER_cert(pem)
565 p2 = ssl.DER_cert_to_PEM_cert(d1)
566 d2 = ssl.PEM_cert_to_DER_cert(p2)
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000567 self.assertEqual(d1, d2)
Antoine Pitrou9bfbe612010-04-27 22:08:08 +0000568 if not p2.startswith(ssl.PEM_HEADER + '\n'):
569 self.fail("DER-to-PEM didn't include correct header:\n%r\n" % p2)
570 if not p2.endswith('\n' + ssl.PEM_FOOTER + '\n'):
571 self.fail("DER-to-PEM didn't include correct footer:\n%r\n" % p2)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000572
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000573 def test_openssl_version(self):
574 n = ssl.OPENSSL_VERSION_NUMBER
575 t = ssl.OPENSSL_VERSION_INFO
576 s = ssl.OPENSSL_VERSION
577 self.assertIsInstance(n, int)
578 self.assertIsInstance(t, tuple)
579 self.assertIsInstance(s, str)
580 # Some sanity checks follow
581 # >= 0.9
582 self.assertGreaterEqual(n, 0x900000)
Christian Heimes2b7de662019-12-07 17:59:36 +0100583 # < 4.0
584 self.assertLess(n, 0x40000000)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000585 major, minor, fix, patch, status = t
Christian Heimes2b7de662019-12-07 17:59:36 +0100586 self.assertGreaterEqual(major, 1)
587 self.assertLess(major, 4)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000588 self.assertGreaterEqual(minor, 0)
589 self.assertLess(minor, 256)
590 self.assertGreaterEqual(fix, 0)
591 self.assertLess(fix, 256)
592 self.assertGreaterEqual(patch, 0)
Ned Deily05784a72015-02-05 17:20:13 +1100593 self.assertLessEqual(patch, 63)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000594 self.assertGreaterEqual(status, 0)
595 self.assertLessEqual(status, 15)
Antoine Pitroudfab9352014-07-21 18:35:01 -0400596 # Version string as returned by {Open,Libre}SSL, the format might change
Christian Heimes598894f2016-09-05 23:19:05 +0200597 if IS_LIBRESSL:
598 self.assertTrue(s.startswith("LibreSSL {:d}".format(major)),
Victor Stinner789b8052015-01-06 11:51:06 +0100599 (s, t, hex(n)))
Antoine Pitroudfab9352014-07-21 18:35:01 -0400600 else:
601 self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)),
Victor Stinner789b8052015-01-06 11:51:06 +0100602 (s, t, hex(n)))
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000603
Antoine Pitrou9d543662010-04-23 23:10:32 +0000604 @support.cpython_only
605 def test_refcycle(self):
606 # Issue #7943: an SSL object doesn't create reference cycles with
607 # itself.
608 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200609 ss = test_wrap_socket(s)
Antoine Pitrou9d543662010-04-23 23:10:32 +0000610 wr = weakref.ref(ss)
Hai Shia7f5d932020-08-04 00:41:24 +0800611 with warnings_helper.check_warnings(("", ResourceWarning)):
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100612 del ss
Victor Stinnere0b75b72016-03-21 17:26:04 +0100613 self.assertEqual(wr(), None)
Antoine Pitrou9d543662010-04-23 23:10:32 +0000614
Antoine Pitroua468adc2010-09-14 14:43:44 +0000615 def test_wrapped_unconnected(self):
616 # Methods on an unconnected SSLSocket propagate the original
Andrew Svetlov0832af62012-12-18 23:10:48 +0200617 # OSError raise by the underlying socket object.
Antoine Pitroua468adc2010-09-14 14:43:44 +0000618 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200619 with test_wrap_socket(s) as ss:
Antoine Pitroue9bb4732013-01-12 21:56:56 +0100620 self.assertRaises(OSError, ss.recv, 1)
621 self.assertRaises(OSError, ss.recv_into, bytearray(b'x'))
622 self.assertRaises(OSError, ss.recvfrom, 1)
623 self.assertRaises(OSError, ss.recvfrom_into, bytearray(b'x'), 1)
624 self.assertRaises(OSError, ss.send, b'x')
625 self.assertRaises(OSError, ss.sendto, b'x', ('0.0.0.0', 0))
Serhiy Storchaka42b1d612018-12-06 22:36:55 +0200626 self.assertRaises(NotImplementedError, ss.dup)
Christian Heimes141c5e82018-02-24 21:10:57 +0100627 self.assertRaises(NotImplementedError, ss.sendmsg,
628 [b'x'], (), 0, ('0.0.0.0', 0))
Serhiy Storchaka42b1d612018-12-06 22:36:55 +0200629 self.assertRaises(NotImplementedError, ss.recvmsg, 100)
630 self.assertRaises(NotImplementedError, ss.recvmsg_into,
631 [bytearray(100)])
Antoine Pitroua468adc2010-09-14 14:43:44 +0000632
Antoine Pitrou40f08742010-04-24 22:04:40 +0000633 def test_timeout(self):
634 # Issue #8524: when creating an SSL socket, the timeout of the
635 # original socket should be retained.
636 for timeout in (None, 0.0, 5.0):
637 s = socket.socket(socket.AF_INET)
638 s.settimeout(timeout)
Christian Heimesd0486372016-09-10 23:23:33 +0200639 with test_wrap_socket(s) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100640 self.assertEqual(timeout, ss.gettimeout())
Antoine Pitrou40f08742010-04-24 22:04:40 +0000641
Christian Heimesd0486372016-09-10 23:23:33 +0200642 def test_errors_sslwrap(self):
Giampaolo Rodolà745ab382010-08-29 19:25:49 +0000643 sock = socket.socket()
Ezio Melottied3a7d22010-12-01 02:32:32 +0000644 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000645 "certfile must be specified",
646 ssl.wrap_socket, sock, keyfile=CERTFILE)
Ezio Melottied3a7d22010-12-01 02:32:32 +0000647 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000648 "certfile must be specified for server-side operations",
649 ssl.wrap_socket, sock, server_side=True)
Ezio Melottied3a7d22010-12-01 02:32:32 +0000650 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000651 "certfile must be specified for server-side operations",
Christian Heimesd0486372016-09-10 23:23:33 +0200652 ssl.wrap_socket, sock, server_side=True, certfile="")
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100653 with ssl.wrap_socket(sock, server_side=True, certfile=CERTFILE) as s:
654 self.assertRaisesRegex(ValueError, "can't connect in server-side mode",
Christian Heimesd0486372016-09-10 23:23:33 +0200655 s.connect, (HOST, 8080))
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200656 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000657 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000658 ssl.wrap_socket(sock, certfile=NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +0000659 self.assertEqual(cm.exception.errno, errno.ENOENT)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200660 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000661 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000662 ssl.wrap_socket(sock,
663 certfile=CERTFILE, keyfile=NONEXISTINGCERT)
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000664 self.assertEqual(cm.exception.errno, errno.ENOENT)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200665 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000666 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000667 ssl.wrap_socket(sock,
668 certfile=NONEXISTINGCERT, keyfile=NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +0000669 self.assertEqual(cm.exception.errno, errno.ENOENT)
Giampaolo Rodolà745ab382010-08-29 19:25:49 +0000670
Martin Panter3464ea22016-02-01 21:58:11 +0000671 def bad_cert_test(self, certfile):
672 """Check that trying to use the given client certificate fails"""
673 certfile = os.path.join(os.path.dirname(__file__) or os.curdir,
674 certfile)
675 sock = socket.socket()
676 self.addCleanup(sock.close)
677 with self.assertRaises(ssl.SSLError):
Christian Heimesd0486372016-09-10 23:23:33 +0200678 test_wrap_socket(sock,
Christian Heimesa170fa12017-09-15 20:27:30 +0200679 certfile=certfile)
Martin Panter3464ea22016-02-01 21:58:11 +0000680
681 def test_empty_cert(self):
682 """Wrapping with an empty cert file"""
683 self.bad_cert_test("nullcert.pem")
684
685 def test_malformed_cert(self):
686 """Wrapping with a badly formatted certificate (syntax error)"""
687 self.bad_cert_test("badcert.pem")
688
689 def test_malformed_key(self):
690 """Wrapping with a badly formatted key (syntax error)"""
691 self.bad_cert_test("badkey.pem")
692
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000693 def test_match_hostname(self):
694 def ok(cert, hostname):
695 ssl.match_hostname(cert, hostname)
696 def fail(cert, hostname):
697 self.assertRaises(ssl.CertificateError,
698 ssl.match_hostname, cert, hostname)
699
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100700 # -- Hostname matching --
701
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000702 cert = {'subject': ((('commonName', 'example.com'),),)}
703 ok(cert, 'example.com')
704 ok(cert, 'ExAmple.cOm')
705 fail(cert, 'www.example.com')
706 fail(cert, '.example.com')
707 fail(cert, 'example.org')
708 fail(cert, 'exampleXcom')
709
710 cert = {'subject': ((('commonName', '*.a.com'),),)}
711 ok(cert, 'foo.a.com')
712 fail(cert, 'bar.foo.a.com')
713 fail(cert, 'a.com')
714 fail(cert, 'Xa.com')
715 fail(cert, '.a.com')
716
Mandeep Singhede2ac92017-11-27 04:01:27 +0530717 # only match wildcards when they are the only thing
718 # in left-most segment
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000719 cert = {'subject': ((('commonName', 'f*.com'),),)}
Mandeep Singhede2ac92017-11-27 04:01:27 +0530720 fail(cert, 'foo.com')
721 fail(cert, 'f.com')
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000722 fail(cert, 'bar.com')
723 fail(cert, 'foo.a.com')
724 fail(cert, 'bar.foo.com')
725
Christian Heimes824f7f32013-08-17 00:54:47 +0200726 # NULL bytes are bad, CVE-2013-4073
727 cert = {'subject': ((('commonName',
728 'null.python.org\x00example.org'),),)}
729 ok(cert, 'null.python.org\x00example.org') # or raise an error?
730 fail(cert, 'example.org')
731 fail(cert, 'null.python.org')
732
Georg Brandl72c98d32013-10-27 07:16:53 +0100733 # error cases with wildcards
734 cert = {'subject': ((('commonName', '*.*.a.com'),),)}
735 fail(cert, 'bar.foo.a.com')
736 fail(cert, 'a.com')
737 fail(cert, 'Xa.com')
738 fail(cert, '.a.com')
739
740 cert = {'subject': ((('commonName', 'a.*.com'),),)}
741 fail(cert, 'a.foo.com')
742 fail(cert, 'a..com')
743 fail(cert, 'a.com')
744
745 # wildcard doesn't match IDNA prefix 'xn--'
746 idna = 'püthon.python.org'.encode("idna").decode("ascii")
747 cert = {'subject': ((('commonName', idna),),)}
748 ok(cert, idna)
749 cert = {'subject': ((('commonName', 'x*.python.org'),),)}
750 fail(cert, idna)
751 cert = {'subject': ((('commonName', 'xn--p*.python.org'),),)}
752 fail(cert, idna)
753
754 # wildcard in first fragment and IDNA A-labels in sequent fragments
755 # are supported.
756 idna = 'www*.pythön.org'.encode("idna").decode("ascii")
757 cert = {'subject': ((('commonName', idna),),)}
Mandeep Singhede2ac92017-11-27 04:01:27 +0530758 fail(cert, 'www.pythön.org'.encode("idna").decode("ascii"))
759 fail(cert, 'www1.pythön.org'.encode("idna").decode("ascii"))
Georg Brandl72c98d32013-10-27 07:16:53 +0100760 fail(cert, 'ftp.pythön.org'.encode("idna").decode("ascii"))
761 fail(cert, 'pythön.org'.encode("idna").decode("ascii"))
762
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000763 # Slightly fake real-world example
764 cert = {'notAfter': 'Jun 26 21:41:46 2011 GMT',
765 'subject': ((('commonName', 'linuxfrz.org'),),),
766 'subjectAltName': (('DNS', 'linuxfr.org'),
767 ('DNS', 'linuxfr.com'),
768 ('othername', '<unsupported>'))}
769 ok(cert, 'linuxfr.org')
770 ok(cert, 'linuxfr.com')
771 # Not a "DNS" entry
772 fail(cert, '<unsupported>')
773 # When there is a subjectAltName, commonName isn't used
774 fail(cert, 'linuxfrz.org')
775
776 # A pristine real-world example
777 cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT',
778 'subject': ((('countryName', 'US'),),
779 (('stateOrProvinceName', 'California'),),
780 (('localityName', 'Mountain View'),),
781 (('organizationName', 'Google Inc'),),
782 (('commonName', 'mail.google.com'),))}
783 ok(cert, 'mail.google.com')
784 fail(cert, 'gmail.com')
785 # Only commonName is considered
786 fail(cert, 'California')
787
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100788 # -- IPv4 matching --
789 cert = {'subject': ((('commonName', 'example.com'),),),
790 'subjectAltName': (('DNS', 'example.com'),
791 ('IP Address', '10.11.12.13'),
Christian Heimes477b1b22019-07-02 20:39:42 +0200792 ('IP Address', '14.15.16.17'),
793 ('IP Address', '127.0.0.1'))}
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100794 ok(cert, '10.11.12.13')
795 ok(cert, '14.15.16.17')
Christian Heimes477b1b22019-07-02 20:39:42 +0200796 # socket.inet_ntoa(socket.inet_aton('127.1')) == '127.0.0.1'
797 fail(cert, '127.1')
798 fail(cert, '14.15.16.17 ')
799 fail(cert, '14.15.16.17 extra data')
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100800 fail(cert, '14.15.16.18')
801 fail(cert, 'example.net')
802
803 # -- IPv6 matching --
Serhiy Storchaka16994912020-04-25 10:06:29 +0300804 if socket_helper.IPV6_ENABLED:
Christian Heimesaef12832018-02-24 14:35:56 +0100805 cert = {'subject': ((('commonName', 'example.com'),),),
806 'subjectAltName': (
807 ('DNS', 'example.com'),
808 ('IP Address', '2001:0:0:0:0:0:0:CAFE\n'),
809 ('IP Address', '2003:0:0:0:0:0:0:BABA\n'))}
810 ok(cert, '2001::cafe')
811 ok(cert, '2003::baba')
Christian Heimes477b1b22019-07-02 20:39:42 +0200812 fail(cert, '2003::baba ')
813 fail(cert, '2003::baba extra data')
Christian Heimesaef12832018-02-24 14:35:56 +0100814 fail(cert, '2003::bebe')
815 fail(cert, 'example.net')
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100816
817 # -- Miscellaneous --
818
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000819 # Neither commonName nor subjectAltName
820 cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT',
821 'subject': ((('countryName', 'US'),),
822 (('stateOrProvinceName', 'California'),),
823 (('localityName', 'Mountain View'),),
824 (('organizationName', 'Google Inc'),))}
825 fail(cert, 'mail.google.com')
826
Antoine Pitrou1c86b442011-05-06 15:19:49 +0200827 # No DNS entry in subjectAltName but a commonName
828 cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT',
829 'subject': ((('countryName', 'US'),),
830 (('stateOrProvinceName', 'California'),),
831 (('localityName', 'Mountain View'),),
832 (('commonName', 'mail.google.com'),)),
833 'subjectAltName': (('othername', 'blabla'), )}
834 ok(cert, 'mail.google.com')
835
836 # No DNS entry subjectAltName and no commonName
837 cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT',
838 'subject': ((('countryName', 'US'),),
839 (('stateOrProvinceName', 'California'),),
840 (('localityName', 'Mountain View'),),
841 (('organizationName', 'Google Inc'),)),
842 'subjectAltName': (('othername', 'blabla'),)}
843 fail(cert, 'google.com')
844
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000845 # Empty cert / no cert
846 self.assertRaises(ValueError, ssl.match_hostname, None, 'example.com')
847 self.assertRaises(ValueError, ssl.match_hostname, {}, 'example.com')
848
Antoine Pitrou636f93c2013-05-18 17:56:42 +0200849 # Issue #17980: avoid denials of service by refusing more than one
850 # wildcard per fragment.
Christian Heimesaef12832018-02-24 14:35:56 +0100851 cert = {'subject': ((('commonName', 'a*b.example.com'),),)}
852 with self.assertRaisesRegex(
853 ssl.CertificateError,
854 "partial wildcards in leftmost label are not supported"):
855 ssl.match_hostname(cert, 'axxb.example.com')
856
857 cert = {'subject': ((('commonName', 'www.*.example.com'),),)}
858 with self.assertRaisesRegex(
859 ssl.CertificateError,
860 "wildcard can only be present in the leftmost label"):
861 ssl.match_hostname(cert, 'www.sub.example.com')
862
863 cert = {'subject': ((('commonName', 'a*b*.example.com'),),)}
864 with self.assertRaisesRegex(
865 ssl.CertificateError,
866 "too many wildcards"):
867 ssl.match_hostname(cert, 'axxbxxc.example.com')
868
869 cert = {'subject': ((('commonName', '*'),),)}
870 with self.assertRaisesRegex(
871 ssl.CertificateError,
872 "sole wildcard without additional labels are not support"):
873 ssl.match_hostname(cert, 'host')
874
875 cert = {'subject': ((('commonName', '*.com'),),)}
876 with self.assertRaisesRegex(
877 ssl.CertificateError,
878 r"hostname 'com' doesn't match '\*.com'"):
879 ssl.match_hostname(cert, 'com')
880
881 # extra checks for _inet_paton()
882 for invalid in ['1', '', '1.2.3', '256.0.0.1', '127.0.0.1/24']:
883 with self.assertRaises(ValueError):
884 ssl._inet_paton(invalid)
885 for ipaddr in ['127.0.0.1', '192.168.0.1']:
886 self.assertTrue(ssl._inet_paton(ipaddr))
Serhiy Storchaka16994912020-04-25 10:06:29 +0300887 if socket_helper.IPV6_ENABLED:
Christian Heimesaef12832018-02-24 14:35:56 +0100888 for ipaddr in ['::1', '2001:db8:85a3::8a2e:370:7334']:
889 self.assertTrue(ssl._inet_paton(ipaddr))
Antoine Pitrou636f93c2013-05-18 17:56:42 +0200890
Antoine Pitroud5323212010-10-22 18:19:07 +0000891 def test_server_side(self):
892 # server_hostname doesn't work for server sockets
Christian Heimesa170fa12017-09-15 20:27:30 +0200893 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroud2eca372010-10-29 23:41:37 +0000894 with socket.socket() as sock:
895 self.assertRaises(ValueError, ctx.wrap_socket, sock, True,
896 server_hostname="some.hostname")
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000897
Antoine Pitroud6494802011-07-21 01:11:30 +0200898 def test_unknown_channel_binding(self):
899 # should raise ValueError for unknown type
Giampaolo Rodolaeb7e29f2019-04-09 00:34:02 +0200900 s = socket.create_server(('127.0.0.1', 0))
Antoine Pitroub1fdf472014-10-05 20:41:53 +0200901 c = socket.socket(socket.AF_INET)
902 c.connect(s.getsockname())
Christian Heimesd0486372016-09-10 23:23:33 +0200903 with test_wrap_socket(c, do_handshake_on_connect=False) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100904 with self.assertRaises(ValueError):
905 ss.get_channel_binding("unknown-type")
Antoine Pitroub1fdf472014-10-05 20:41:53 +0200906 s.close()
Antoine Pitroud6494802011-07-21 01:11:30 +0200907
908 @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES,
909 "'tls-unique' channel binding not available")
910 def test_tls_unique_channel_binding(self):
911 # unconnected should return None for known type
912 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200913 with test_wrap_socket(s) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100914 self.assertIsNone(ss.get_channel_binding("tls-unique"))
Antoine Pitroud6494802011-07-21 01:11:30 +0200915 # the same for server-side
916 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200917 with test_wrap_socket(s, server_side=True, certfile=CERTFILE) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100918 self.assertIsNone(ss.get_channel_binding("tls-unique"))
Antoine Pitroud6494802011-07-21 01:11:30 +0200919
Benjamin Peterson36f7b972013-01-10 14:16:20 -0600920 def test_dealloc_warn(self):
Christian Heimesd0486372016-09-10 23:23:33 +0200921 ss = test_wrap_socket(socket.socket(socket.AF_INET))
Benjamin Peterson36f7b972013-01-10 14:16:20 -0600922 r = repr(ss)
923 with self.assertWarns(ResourceWarning) as cm:
924 ss = None
925 support.gc_collect()
926 self.assertIn(r, str(cm.warning.args[0]))
927
Christian Heimes6d7ad132013-06-09 18:02:55 +0200928 def test_get_default_verify_paths(self):
929 paths = ssl.get_default_verify_paths()
930 self.assertEqual(len(paths), 6)
931 self.assertIsInstance(paths, ssl.DefaultVerifyPaths)
932
Hai Shia7f5d932020-08-04 00:41:24 +0800933 with os_helper.EnvironmentVarGuard() as env:
Christian Heimes6d7ad132013-06-09 18:02:55 +0200934 env["SSL_CERT_DIR"] = CAPATH
935 env["SSL_CERT_FILE"] = CERTFILE
936 paths = ssl.get_default_verify_paths()
937 self.assertEqual(paths.cafile, CERTFILE)
938 self.assertEqual(paths.capath, CAPATH)
939
Christian Heimes44109d72013-11-22 01:51:30 +0100940 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
941 def test_enum_certificates(self):
942 self.assertTrue(ssl.enum_certificates("CA"))
943 self.assertTrue(ssl.enum_certificates("ROOT"))
944
945 self.assertRaises(TypeError, ssl.enum_certificates)
946 self.assertRaises(WindowsError, ssl.enum_certificates, "")
947
Christian Heimesc2d65e12013-11-22 16:13:55 +0100948 trust_oids = set()
949 for storename in ("CA", "ROOT"):
950 store = ssl.enum_certificates(storename)
951 self.assertIsInstance(store, list)
952 for element in store:
953 self.assertIsInstance(element, tuple)
954 self.assertEqual(len(element), 3)
955 cert, enc, trust = element
956 self.assertIsInstance(cert, bytes)
957 self.assertIn(enc, {"x509_asn", "pkcs_7_asn"})
Christian Heimes915cd3f2019-09-09 18:06:55 +0200958 self.assertIsInstance(trust, (frozenset, set, bool))
959 if isinstance(trust, (frozenset, set)):
Christian Heimesc2d65e12013-11-22 16:13:55 +0100960 trust_oids.update(trust)
Christian Heimes44109d72013-11-22 01:51:30 +0100961
962 serverAuth = "1.3.6.1.5.5.7.3.1"
Christian Heimesc2d65e12013-11-22 16:13:55 +0100963 self.assertIn(serverAuth, trust_oids)
Christian Heimes6d7ad132013-06-09 18:02:55 +0200964
Christian Heimes46bebee2013-06-09 19:03:31 +0200965 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
Christian Heimes44109d72013-11-22 01:51:30 +0100966 def test_enum_crls(self):
967 self.assertTrue(ssl.enum_crls("CA"))
968 self.assertRaises(TypeError, ssl.enum_crls)
969 self.assertRaises(WindowsError, ssl.enum_crls, "")
Christian Heimes46bebee2013-06-09 19:03:31 +0200970
Christian Heimes44109d72013-11-22 01:51:30 +0100971 crls = ssl.enum_crls("CA")
972 self.assertIsInstance(crls, list)
973 for element in crls:
974 self.assertIsInstance(element, tuple)
975 self.assertEqual(len(element), 2)
976 self.assertIsInstance(element[0], bytes)
977 self.assertIn(element[1], {"x509_asn", "pkcs_7_asn"})
Christian Heimes46bebee2013-06-09 19:03:31 +0200978
Christian Heimes46bebee2013-06-09 19:03:31 +0200979
Christian Heimesa6bc95a2013-11-17 19:59:14 +0100980 def test_asn1object(self):
981 expected = (129, 'serverAuth', 'TLS Web Server Authentication',
982 '1.3.6.1.5.5.7.3.1')
983
984 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1')
985 self.assertEqual(val, expected)
986 self.assertEqual(val.nid, 129)
987 self.assertEqual(val.shortname, 'serverAuth')
988 self.assertEqual(val.longname, 'TLS Web Server Authentication')
989 self.assertEqual(val.oid, '1.3.6.1.5.5.7.3.1')
990 self.assertIsInstance(val, ssl._ASN1Object)
991 self.assertRaises(ValueError, ssl._ASN1Object, 'serverAuth')
992
993 val = ssl._ASN1Object.fromnid(129)
994 self.assertEqual(val, expected)
995 self.assertIsInstance(val, ssl._ASN1Object)
996 self.assertRaises(ValueError, ssl._ASN1Object.fromnid, -1)
Christian Heimes5398e1a2013-11-22 16:20:53 +0100997 with self.assertRaisesRegex(ValueError, "unknown NID 100000"):
998 ssl._ASN1Object.fromnid(100000)
Christian Heimesa6bc95a2013-11-17 19:59:14 +0100999 for i in range(1000):
1000 try:
1001 obj = ssl._ASN1Object.fromnid(i)
1002 except ValueError:
1003 pass
1004 else:
1005 self.assertIsInstance(obj.nid, int)
1006 self.assertIsInstance(obj.shortname, str)
1007 self.assertIsInstance(obj.longname, str)
1008 self.assertIsInstance(obj.oid, (str, type(None)))
1009
1010 val = ssl._ASN1Object.fromname('TLS Web Server Authentication')
1011 self.assertEqual(val, expected)
1012 self.assertIsInstance(val, ssl._ASN1Object)
1013 self.assertEqual(ssl._ASN1Object.fromname('serverAuth'), expected)
1014 self.assertEqual(ssl._ASN1Object.fromname('1.3.6.1.5.5.7.3.1'),
1015 expected)
Christian Heimes5398e1a2013-11-22 16:20:53 +01001016 with self.assertRaisesRegex(ValueError, "unknown object 'serverauth'"):
1017 ssl._ASN1Object.fromname('serverauth')
Christian Heimesa6bc95a2013-11-17 19:59:14 +01001018
Christian Heimes72d28502013-11-23 13:56:58 +01001019 def test_purpose_enum(self):
1020 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1')
1021 self.assertIsInstance(ssl.Purpose.SERVER_AUTH, ssl._ASN1Object)
1022 self.assertEqual(ssl.Purpose.SERVER_AUTH, val)
1023 self.assertEqual(ssl.Purpose.SERVER_AUTH.nid, 129)
1024 self.assertEqual(ssl.Purpose.SERVER_AUTH.shortname, 'serverAuth')
1025 self.assertEqual(ssl.Purpose.SERVER_AUTH.oid,
1026 '1.3.6.1.5.5.7.3.1')
1027
1028 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.2')
1029 self.assertIsInstance(ssl.Purpose.CLIENT_AUTH, ssl._ASN1Object)
1030 self.assertEqual(ssl.Purpose.CLIENT_AUTH, val)
1031 self.assertEqual(ssl.Purpose.CLIENT_AUTH.nid, 130)
1032 self.assertEqual(ssl.Purpose.CLIENT_AUTH.shortname, 'clientAuth')
1033 self.assertEqual(ssl.Purpose.CLIENT_AUTH.oid,
1034 '1.3.6.1.5.5.7.3.2')
1035
Antoine Pitrou3e86ba42013-12-28 17:26:33 +01001036 def test_unsupported_dtls(self):
1037 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
1038 self.addCleanup(s.close)
1039 with self.assertRaises(NotImplementedError) as cx:
Christian Heimesd0486372016-09-10 23:23:33 +02001040 test_wrap_socket(s, cert_reqs=ssl.CERT_NONE)
Antoine Pitrou3e86ba42013-12-28 17:26:33 +01001041 self.assertEqual(str(cx.exception), "only stream sockets are supported")
Christian Heimesa170fa12017-09-15 20:27:30 +02001042 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou3e86ba42013-12-28 17:26:33 +01001043 with self.assertRaises(NotImplementedError) as cx:
1044 ctx.wrap_socket(s)
1045 self.assertEqual(str(cx.exception), "only stream sockets are supported")
1046
Antoine Pitrouc695c952014-04-28 20:57:36 +02001047 def cert_time_ok(self, timestring, timestamp):
1048 self.assertEqual(ssl.cert_time_to_seconds(timestring), timestamp)
1049
1050 def cert_time_fail(self, timestring):
1051 with self.assertRaises(ValueError):
1052 ssl.cert_time_to_seconds(timestring)
1053
1054 @unittest.skipUnless(utc_offset(),
1055 'local time needs to be different from UTC')
1056 def test_cert_time_to_seconds_timezone(self):
1057 # Issue #19940: ssl.cert_time_to_seconds() returns wrong
1058 # results if local timezone is not UTC
1059 self.cert_time_ok("May 9 00:00:00 2007 GMT", 1178668800.0)
1060 self.cert_time_ok("Jan 5 09:34:43 2018 GMT", 1515144883.0)
1061
1062 def test_cert_time_to_seconds(self):
1063 timestring = "Jan 5 09:34:43 2018 GMT"
1064 ts = 1515144883.0
1065 self.cert_time_ok(timestring, ts)
1066 # accept keyword parameter, assert its name
1067 self.assertEqual(ssl.cert_time_to_seconds(cert_time=timestring), ts)
1068 # accept both %e and %d (space or zero generated by strftime)
1069 self.cert_time_ok("Jan 05 09:34:43 2018 GMT", ts)
1070 # case-insensitive
1071 self.cert_time_ok("JaN 5 09:34:43 2018 GmT", ts)
1072 self.cert_time_fail("Jan 5 09:34 2018 GMT") # no seconds
1073 self.cert_time_fail("Jan 5 09:34:43 2018") # no GMT
1074 self.cert_time_fail("Jan 5 09:34:43 2018 UTC") # not GMT timezone
1075 self.cert_time_fail("Jan 35 09:34:43 2018 GMT") # invalid day
1076 self.cert_time_fail("Jon 5 09:34:43 2018 GMT") # invalid month
1077 self.cert_time_fail("Jan 5 24:00:00 2018 GMT") # invalid hour
1078 self.cert_time_fail("Jan 5 09:60:43 2018 GMT") # invalid minute
1079
1080 newyear_ts = 1230768000.0
1081 # leap seconds
1082 self.cert_time_ok("Dec 31 23:59:60 2008 GMT", newyear_ts)
1083 # same timestamp
1084 self.cert_time_ok("Jan 1 00:00:00 2009 GMT", newyear_ts)
1085
1086 self.cert_time_ok("Jan 5 09:34:59 2018 GMT", 1515144899)
1087 # allow 60th second (even if it is not a leap second)
1088 self.cert_time_ok("Jan 5 09:34:60 2018 GMT", 1515144900)
1089 # allow 2nd leap second for compatibility with time.strptime()
1090 self.cert_time_ok("Jan 5 09:34:61 2018 GMT", 1515144901)
1091 self.cert_time_fail("Jan 5 09:34:62 2018 GMT") # invalid seconds
1092
Mike53f7a7c2017-12-14 14:04:53 +03001093 # no special treatment for the special value:
Antoine Pitrouc695c952014-04-28 20:57:36 +02001094 # 99991231235959Z (rfc 5280)
1095 self.cert_time_ok("Dec 31 23:59:59 9999 GMT", 253402300799.0)
1096
1097 @support.run_with_locale('LC_ALL', '')
1098 def test_cert_time_to_seconds_locale(self):
1099 # `cert_time_to_seconds()` should be locale independent
1100
1101 def local_february_name():
1102 return time.strftime('%b', (1, 2, 3, 4, 5, 6, 0, 0, 0))
1103
1104 if local_february_name().lower() == 'feb':
1105 self.skipTest("locale-specific month name needs to be "
1106 "different from C locale")
1107
1108 # locale-independent
1109 self.cert_time_ok("Feb 9 00:00:00 2007 GMT", 1170979200.0)
1110 self.cert_time_fail(local_february_name() + " 9 00:00:00 2007 GMT")
1111
Martin Panter3840b2a2016-03-27 01:53:46 +00001112 def test_connect_ex_error(self):
1113 server = socket.socket(socket.AF_INET)
1114 self.addCleanup(server.close)
Serhiy Storchaka16994912020-04-25 10:06:29 +03001115 port = socket_helper.bind_port(server) # Reserve port but don't listen
Christian Heimesd0486372016-09-10 23:23:33 +02001116 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001117 cert_reqs=ssl.CERT_REQUIRED)
1118 self.addCleanup(s.close)
1119 rc = s.connect_ex((HOST, port))
1120 # Issue #19919: Windows machines or VMs hosted on Windows
1121 # machines sometimes return EWOULDBLOCK.
1122 errors = (
1123 errno.ECONNREFUSED, errno.EHOSTUNREACH, errno.ETIMEDOUT,
1124 errno.EWOULDBLOCK,
1125 )
1126 self.assertIn(rc, errors)
1127
Christian Heimesa6bc95a2013-11-17 19:59:14 +01001128
Antoine Pitrou152efa22010-05-16 18:19:27 +00001129class ContextTests(unittest.TestCase):
1130
1131 def test_constructor(self):
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01001132 for protocol in PROTOCOLS:
1133 ssl.SSLContext(protocol)
Christian Heimes598894f2016-09-05 23:19:05 +02001134 ctx = ssl.SSLContext()
1135 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001136 self.assertRaises(ValueError, ssl.SSLContext, -1)
1137 self.assertRaises(ValueError, ssl.SSLContext, 42)
1138
1139 def test_protocol(self):
1140 for proto in PROTOCOLS:
1141 ctx = ssl.SSLContext(proto)
1142 self.assertEqual(ctx.protocol, proto)
1143
1144 def test_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001145 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001146 ctx.set_ciphers("ALL")
1147 ctx.set_ciphers("DEFAULT")
Ezio Melottied3a7d22010-12-01 02:32:32 +00001148 with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
Antoine Pitrou30474062010-05-16 23:46:26 +00001149 ctx.set_ciphers("^$:,;?*'dorothyx")
Antoine Pitrou152efa22010-05-16 18:19:27 +00001150
Christian Heimes892d66e2018-01-29 14:10:18 +01001151 @unittest.skipUnless(PY_SSL_DEFAULT_CIPHERS == 1,
1152 "Test applies only to Python default ciphers")
1153 def test_python_ciphers(self):
1154 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1155 ciphers = ctx.get_ciphers()
1156 for suite in ciphers:
1157 name = suite['name']
1158 self.assertNotIn("PSK", name)
1159 self.assertNotIn("SRP", name)
1160 self.assertNotIn("MD5", name)
1161 self.assertNotIn("RC4", name)
1162 self.assertNotIn("3DES", name)
1163
Christian Heimes25bfcd52016-09-06 00:04:45 +02001164 @unittest.skipIf(ssl.OPENSSL_VERSION_INFO < (1, 0, 2, 0, 0), 'OpenSSL too old')
1165 def test_get_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001166 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesea9b2dc2016-09-06 10:45:44 +02001167 ctx.set_ciphers('AESGCM')
Christian Heimes25bfcd52016-09-06 00:04:45 +02001168 names = set(d['name'] for d in ctx.get_ciphers())
Christian Heimes582282b2016-09-06 11:27:25 +02001169 self.assertIn('AES256-GCM-SHA384', names)
1170 self.assertIn('AES128-GCM-SHA256', names)
Christian Heimes25bfcd52016-09-06 00:04:45 +02001171
Antoine Pitroub5218772010-05-21 09:56:06 +00001172 def test_options(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001173 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Benjamin Petersona9dcdab2015-11-11 22:38:41 -08001174 # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value
Christian Heimes598894f2016-09-05 23:19:05 +02001175 default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
Christian Heimes358cfd42016-09-10 22:43:48 +02001176 # SSLContext also enables these by default
1177 default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE |
Christian Heimes05d9fe32018-02-27 08:55:39 +01001178 OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE |
Christian Heimes6f37ebc2021-04-09 17:59:21 +02001179 OP_ENABLE_MIDDLEBOX_COMPAT |
1180 OP_IGNORE_UNEXPECTED_EOF)
Christian Heimes598894f2016-09-05 23:19:05 +02001181 self.assertEqual(default, ctx.options)
Benjamin Petersona9dcdab2015-11-11 22:38:41 -08001182 ctx.options |= ssl.OP_NO_TLSv1
Christian Heimes598894f2016-09-05 23:19:05 +02001183 self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options)
Antoine Pitroub5218772010-05-21 09:56:06 +00001184 if can_clear_options():
Christian Heimes598894f2016-09-05 23:19:05 +02001185 ctx.options = (ctx.options & ~ssl.OP_NO_TLSv1)
1186 self.assertEqual(default, ctx.options)
Antoine Pitroub5218772010-05-21 09:56:06 +00001187 ctx.options = 0
Matthias Klosef7c56242016-06-12 23:40:00 -07001188 # Ubuntu has OP_NO_SSLv3 forced on by default
1189 self.assertEqual(0, ctx.options & ~ssl.OP_NO_SSLv3)
Antoine Pitroub5218772010-05-21 09:56:06 +00001190 else:
1191 with self.assertRaises(ValueError):
1192 ctx.options = 0
1193
Christian Heimesa170fa12017-09-15 20:27:30 +02001194 def test_verify_mode_protocol(self):
1195 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001196 # Default value
1197 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1198 ctx.verify_mode = ssl.CERT_OPTIONAL
1199 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1200 ctx.verify_mode = ssl.CERT_REQUIRED
1201 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1202 ctx.verify_mode = ssl.CERT_NONE
1203 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1204 with self.assertRaises(TypeError):
1205 ctx.verify_mode = None
1206 with self.assertRaises(ValueError):
1207 ctx.verify_mode = 42
1208
Christian Heimesa170fa12017-09-15 20:27:30 +02001209 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1210 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1211 self.assertFalse(ctx.check_hostname)
1212
1213 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1214 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1215 self.assertTrue(ctx.check_hostname)
1216
Christian Heimes61d478c2018-01-27 15:51:38 +01001217 def test_hostname_checks_common_name(self):
1218 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1219 self.assertTrue(ctx.hostname_checks_common_name)
1220 if ssl.HAS_NEVER_CHECK_COMMON_NAME:
1221 ctx.hostname_checks_common_name = True
1222 self.assertTrue(ctx.hostname_checks_common_name)
1223 ctx.hostname_checks_common_name = False
1224 self.assertFalse(ctx.hostname_checks_common_name)
1225 ctx.hostname_checks_common_name = True
1226 self.assertTrue(ctx.hostname_checks_common_name)
1227 else:
1228 with self.assertRaises(AttributeError):
1229 ctx.hostname_checks_common_name = True
Christian Heimesa170fa12017-09-15 20:27:30 +02001230
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001231 @requires_minimum_version
Christian Heimesc9bc49c2019-09-11 19:24:47 +02001232 @unittest.skipIf(IS_LIBRESSL, "see bpo-34001")
Christian Heimes698dde12018-02-27 11:54:43 +01001233 def test_min_max_version(self):
1234 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimes34de2d32019-01-18 16:09:30 +01001235 # OpenSSL default is MINIMUM_SUPPORTED, however some vendors like
1236 # Fedora override the setting to TLS 1.0.
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001237 minimum_range = {
1238 # stock OpenSSL
1239 ssl.TLSVersion.MINIMUM_SUPPORTED,
1240 # Fedora 29 uses TLS 1.0 by default
1241 ssl.TLSVersion.TLSv1,
1242 # RHEL 8 uses TLS 1.2 by default
1243 ssl.TLSVersion.TLSv1_2
1244 }
torsava34864d12019-12-02 17:15:42 +01001245 maximum_range = {
1246 # stock OpenSSL
1247 ssl.TLSVersion.MAXIMUM_SUPPORTED,
1248 # Fedora 32 uses TLS 1.3 by default
1249 ssl.TLSVersion.TLSv1_3
1250 }
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001251
Christian Heimes34de2d32019-01-18 16:09:30 +01001252 self.assertIn(
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001253 ctx.minimum_version, minimum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001254 )
torsava34864d12019-12-02 17:15:42 +01001255 self.assertIn(
1256 ctx.maximum_version, maximum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001257 )
1258
1259 ctx.minimum_version = ssl.TLSVersion.TLSv1_1
1260 ctx.maximum_version = ssl.TLSVersion.TLSv1_2
1261 self.assertEqual(
1262 ctx.minimum_version, ssl.TLSVersion.TLSv1_1
1263 )
1264 self.assertEqual(
1265 ctx.maximum_version, ssl.TLSVersion.TLSv1_2
1266 )
1267
1268 ctx.minimum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1269 ctx.maximum_version = ssl.TLSVersion.TLSv1
1270 self.assertEqual(
1271 ctx.minimum_version, ssl.TLSVersion.MINIMUM_SUPPORTED
1272 )
1273 self.assertEqual(
1274 ctx.maximum_version, ssl.TLSVersion.TLSv1
1275 )
1276
1277 ctx.maximum_version = ssl.TLSVersion.MAXIMUM_SUPPORTED
1278 self.assertEqual(
1279 ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED
1280 )
1281
1282 ctx.maximum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1283 self.assertIn(
1284 ctx.maximum_version,
1285 {ssl.TLSVersion.TLSv1, ssl.TLSVersion.SSLv3}
1286 )
1287
1288 ctx.minimum_version = ssl.TLSVersion.MAXIMUM_SUPPORTED
1289 self.assertIn(
1290 ctx.minimum_version,
1291 {ssl.TLSVersion.TLSv1_2, ssl.TLSVersion.TLSv1_3}
1292 )
1293
1294 with self.assertRaises(ValueError):
1295 ctx.minimum_version = 42
1296
1297 ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_1)
1298
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001299 self.assertIn(
1300 ctx.minimum_version, minimum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001301 )
1302 self.assertEqual(
1303 ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED
1304 )
1305 with self.assertRaises(ValueError):
1306 ctx.minimum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1307 with self.assertRaises(ValueError):
1308 ctx.maximum_version = ssl.TLSVersion.TLSv1
1309
1310
matthewhughes9348e836bb2020-07-17 09:59:15 +01001311 @unittest.skipUnless(
1312 hasattr(ssl.SSLContext, 'security_level'),
1313 "requires OpenSSL >= 1.1.0"
1314 )
1315 def test_security_level(self):
1316 ctx = ssl.SSLContext()
1317 # The default security callback allows for levels between 0-5
1318 # with OpenSSL defaulting to 1, however some vendors override the
1319 # default value (e.g. Debian defaults to 2)
1320 security_level_range = {
1321 0,
1322 1, # OpenSSL default
1323 2, # Debian
1324 3,
1325 4,
1326 5,
1327 }
1328 self.assertIn(ctx.security_level, security_level_range)
1329
Christian Heimes2427b502013-11-23 11:24:32 +01001330 @unittest.skipUnless(have_verify_flags(),
1331 "verify_flags need OpenSSL > 0.9.8")
Christian Heimes22587792013-11-21 23:56:13 +01001332 def test_verify_flags(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001333 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Benjamin Peterson990fcaa2015-03-04 22:49:41 -05001334 # default value
1335 tf = getattr(ssl, "VERIFY_X509_TRUSTED_FIRST", 0)
1336 self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT | tf)
Christian Heimes22587792013-11-21 23:56:13 +01001337 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF
1338 self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_LEAF)
1339 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_CHAIN
1340 self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_CHAIN)
1341 ctx.verify_flags = ssl.VERIFY_DEFAULT
1342 self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT)
Chris Burre0b4aa02021-03-18 09:24:01 +01001343 ctx.verify_flags = ssl.VERIFY_ALLOW_PROXY_CERTS
1344 self.assertEqual(ctx.verify_flags, ssl.VERIFY_ALLOW_PROXY_CERTS)
Christian Heimes22587792013-11-21 23:56:13 +01001345 # supports any value
1346 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT
1347 self.assertEqual(ctx.verify_flags,
1348 ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT)
1349 with self.assertRaises(TypeError):
1350 ctx.verify_flags = None
1351
Antoine Pitrou152efa22010-05-16 18:19:27 +00001352 def test_load_cert_chain(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001353 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001354 # Combined key and cert in a single file
Benjamin Peterson1ea070e2014-11-03 21:05:01 -05001355 ctx.load_cert_chain(CERTFILE, keyfile=None)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001356 ctx.load_cert_chain(CERTFILE, keyfile=CERTFILE)
1357 self.assertRaises(TypeError, ctx.load_cert_chain, keyfile=CERTFILE)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001358 with self.assertRaises(OSError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001359 ctx.load_cert_chain(NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +00001360 self.assertEqual(cm.exception.errno, errno.ENOENT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001361 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001362 ctx.load_cert_chain(BADCERT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001363 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001364 ctx.load_cert_chain(EMPTYCERT)
1365 # Separate key and cert
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_cert_chain(ONLYCERT, ONLYKEY)
1368 ctx.load_cert_chain(certfile=ONLYCERT, keyfile=ONLYKEY)
1369 ctx.load_cert_chain(certfile=BYTES_ONLYCERT, keyfile=BYTES_ONLYKEY)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001370 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001371 ctx.load_cert_chain(ONLYCERT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001372 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001373 ctx.load_cert_chain(ONLYKEY)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001374 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001375 ctx.load_cert_chain(certfile=ONLYKEY, keyfile=ONLYCERT)
1376 # Mismatching key and cert
Christian Heimesa170fa12017-09-15 20:27:30 +02001377 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001378 with self.assertRaisesRegex(ssl.SSLError, "key values mismatch"):
Martin Panter3d81d932016-01-14 09:36:00 +00001379 ctx.load_cert_chain(CAFILE_CACERT, ONLYKEY)
Antoine Pitrou4fd1e6a2011-08-25 14:39:44 +02001380 # Password protected key and cert
1381 ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD)
1382 ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD.encode())
1383 ctx.load_cert_chain(CERTFILE_PROTECTED,
1384 password=bytearray(KEY_PASSWORD.encode()))
1385 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD)
1386 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD.encode())
1387 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED,
1388 bytearray(KEY_PASSWORD.encode()))
1389 with self.assertRaisesRegex(TypeError, "should be a string"):
1390 ctx.load_cert_chain(CERTFILE_PROTECTED, password=True)
1391 with self.assertRaises(ssl.SSLError):
1392 ctx.load_cert_chain(CERTFILE_PROTECTED, password="badpass")
1393 with self.assertRaisesRegex(ValueError, "cannot be longer"):
1394 # openssl has a fixed limit on the password buffer.
1395 # PEM_BUFSIZE is generally set to 1kb.
1396 # Return a string larger than this.
1397 ctx.load_cert_chain(CERTFILE_PROTECTED, password=b'a' * 102400)
1398 # Password callback
1399 def getpass_unicode():
1400 return KEY_PASSWORD
1401 def getpass_bytes():
1402 return KEY_PASSWORD.encode()
1403 def getpass_bytearray():
1404 return bytearray(KEY_PASSWORD.encode())
1405 def getpass_badpass():
1406 return "badpass"
1407 def getpass_huge():
1408 return b'a' * (1024 * 1024)
1409 def getpass_bad_type():
1410 return 9
1411 def getpass_exception():
1412 raise Exception('getpass error')
1413 class GetPassCallable:
1414 def __call__(self):
1415 return KEY_PASSWORD
1416 def getpass(self):
1417 return KEY_PASSWORD
1418 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_unicode)
1419 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytes)
1420 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytearray)
1421 ctx.load_cert_chain(CERTFILE_PROTECTED, password=GetPassCallable())
1422 ctx.load_cert_chain(CERTFILE_PROTECTED,
1423 password=GetPassCallable().getpass)
1424 with self.assertRaises(ssl.SSLError):
1425 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_badpass)
1426 with self.assertRaisesRegex(ValueError, "cannot be longer"):
1427 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_huge)
1428 with self.assertRaisesRegex(TypeError, "must return a string"):
1429 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bad_type)
1430 with self.assertRaisesRegex(Exception, "getpass error"):
1431 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_exception)
1432 # Make sure the password function isn't called if it isn't needed
1433 ctx.load_cert_chain(CERTFILE, password=getpass_exception)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001434
1435 def test_load_verify_locations(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001436 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001437 ctx.load_verify_locations(CERTFILE)
1438 ctx.load_verify_locations(cafile=CERTFILE, capath=None)
1439 ctx.load_verify_locations(BYTES_CERTFILE)
1440 ctx.load_verify_locations(cafile=BYTES_CERTFILE, capath=None)
1441 self.assertRaises(TypeError, ctx.load_verify_locations)
Christian Heimesefff7062013-11-21 03:35:02 +01001442 self.assertRaises(TypeError, ctx.load_verify_locations, None, None, None)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001443 with self.assertRaises(OSError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001444 ctx.load_verify_locations(NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +00001445 self.assertEqual(cm.exception.errno, errno.ENOENT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001446 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001447 ctx.load_verify_locations(BADCERT)
1448 ctx.load_verify_locations(CERTFILE, CAPATH)
1449 ctx.load_verify_locations(CERTFILE, capath=BYTES_CAPATH)
1450
Victor Stinner80f75e62011-01-29 11:31:20 +00001451 # Issue #10989: crash if the second argument type is invalid
1452 self.assertRaises(TypeError, ctx.load_verify_locations, None, True)
1453
Christian Heimesefff7062013-11-21 03:35:02 +01001454 def test_load_verify_cadata(self):
1455 # test cadata
1456 with open(CAFILE_CACERT) as f:
1457 cacert_pem = f.read()
1458 cacert_der = ssl.PEM_cert_to_DER_cert(cacert_pem)
1459 with open(CAFILE_NEURONIO) as f:
1460 neuronio_pem = f.read()
1461 neuronio_der = ssl.PEM_cert_to_DER_cert(neuronio_pem)
1462
1463 # test PEM
Christian Heimesa170fa12017-09-15 20:27:30 +02001464 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001465 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 0)
1466 ctx.load_verify_locations(cadata=cacert_pem)
1467 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 1)
1468 ctx.load_verify_locations(cadata=neuronio_pem)
1469 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1470 # cert already in hash table
1471 ctx.load_verify_locations(cadata=neuronio_pem)
1472 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1473
1474 # combined
Christian Heimesa170fa12017-09-15 20:27:30 +02001475 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001476 combined = "\n".join((cacert_pem, neuronio_pem))
1477 ctx.load_verify_locations(cadata=combined)
1478 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1479
1480 # with junk around the certs
Christian Heimesa170fa12017-09-15 20:27:30 +02001481 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001482 combined = ["head", cacert_pem, "other", neuronio_pem, "again",
1483 neuronio_pem, "tail"]
1484 ctx.load_verify_locations(cadata="\n".join(combined))
1485 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1486
1487 # test DER
Christian Heimesa170fa12017-09-15 20:27:30 +02001488 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001489 ctx.load_verify_locations(cadata=cacert_der)
1490 ctx.load_verify_locations(cadata=neuronio_der)
1491 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1492 # cert already in hash table
1493 ctx.load_verify_locations(cadata=cacert_der)
1494 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1495
1496 # combined
Christian Heimesa170fa12017-09-15 20:27:30 +02001497 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001498 combined = b"".join((cacert_der, neuronio_der))
1499 ctx.load_verify_locations(cadata=combined)
1500 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1501
1502 # error cases
Christian Heimesa170fa12017-09-15 20:27:30 +02001503 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001504 self.assertRaises(TypeError, ctx.load_verify_locations, cadata=object)
1505
1506 with self.assertRaisesRegex(ssl.SSLError, "no start line"):
1507 ctx.load_verify_locations(cadata="broken")
1508 with self.assertRaisesRegex(ssl.SSLError, "not enough data"):
1509 ctx.load_verify_locations(cadata=b"broken")
1510
1511
Paul Monsonf3550692019-06-19 13:09:54 -07001512 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001513 def test_load_dh_params(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001514 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001515 ctx.load_dh_params(DHFILE)
1516 if os.name != 'nt':
1517 ctx.load_dh_params(BYTES_DHFILE)
1518 self.assertRaises(TypeError, ctx.load_dh_params)
1519 self.assertRaises(TypeError, ctx.load_dh_params, None)
1520 with self.assertRaises(FileNotFoundError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001521 ctx.load_dh_params(NONEXISTINGCERT)
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001522 self.assertEqual(cm.exception.errno, errno.ENOENT)
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001523 with self.assertRaises(ssl.SSLError) as cm:
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001524 ctx.load_dh_params(CERTFILE)
1525
Antoine Pitroub0182c82010-10-12 20:09:02 +00001526 def test_session_stats(self):
1527 for proto in PROTOCOLS:
1528 ctx = ssl.SSLContext(proto)
1529 self.assertEqual(ctx.session_stats(), {
1530 'number': 0,
1531 'connect': 0,
1532 'connect_good': 0,
1533 'connect_renegotiate': 0,
1534 'accept': 0,
1535 'accept_good': 0,
1536 'accept_renegotiate': 0,
1537 'hits': 0,
1538 'misses': 0,
1539 'timeouts': 0,
1540 'cache_full': 0,
1541 })
1542
Antoine Pitrou664c2d12010-11-17 20:29:42 +00001543 def test_set_default_verify_paths(self):
1544 # There's not much we can do to test that it acts as expected,
1545 # so just check it doesn't crash or raise an exception.
Christian Heimesa170fa12017-09-15 20:27:30 +02001546 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou664c2d12010-11-17 20:29:42 +00001547 ctx.set_default_verify_paths()
1548
Antoine Pitrou501da612011-12-21 09:27:41 +01001549 @unittest.skipUnless(ssl.HAS_ECDH, "ECDH disabled on this OpenSSL build")
Antoine Pitrou923df6f2011-12-19 17:16:51 +01001550 def test_set_ecdh_curve(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001551 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou923df6f2011-12-19 17:16:51 +01001552 ctx.set_ecdh_curve("prime256v1")
1553 ctx.set_ecdh_curve(b"prime256v1")
1554 self.assertRaises(TypeError, ctx.set_ecdh_curve)
1555 self.assertRaises(TypeError, ctx.set_ecdh_curve, None)
1556 self.assertRaises(ValueError, ctx.set_ecdh_curve, "foo")
1557 self.assertRaises(ValueError, ctx.set_ecdh_curve, b"foo")
1558
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001559 @needs_sni
1560 def test_sni_callback(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001561 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001562
1563 # set_servername_callback expects a callable, or None
1564 self.assertRaises(TypeError, ctx.set_servername_callback)
1565 self.assertRaises(TypeError, ctx.set_servername_callback, 4)
1566 self.assertRaises(TypeError, ctx.set_servername_callback, "")
1567 self.assertRaises(TypeError, ctx.set_servername_callback, ctx)
1568
1569 def dummycallback(sock, servername, ctx):
1570 pass
1571 ctx.set_servername_callback(None)
1572 ctx.set_servername_callback(dummycallback)
1573
1574 @needs_sni
1575 def test_sni_callback_refcycle(self):
1576 # Reference cycles through the servername callback are detected
1577 # and cleared.
Christian Heimesa170fa12017-09-15 20:27:30 +02001578 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001579 def dummycallback(sock, servername, ctx, cycle=ctx):
1580 pass
1581 ctx.set_servername_callback(dummycallback)
1582 wr = weakref.ref(ctx)
1583 del ctx, dummycallback
1584 gc.collect()
1585 self.assertIs(wr(), None)
1586
Christian Heimes9a5395a2013-06-17 15:44:12 +02001587 def test_cert_store_stats(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001588 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001589 self.assertEqual(ctx.cert_store_stats(),
1590 {'x509_ca': 0, 'crl': 0, 'x509': 0})
1591 ctx.load_cert_chain(CERTFILE)
1592 self.assertEqual(ctx.cert_store_stats(),
1593 {'x509_ca': 0, 'crl': 0, 'x509': 0})
1594 ctx.load_verify_locations(CERTFILE)
1595 self.assertEqual(ctx.cert_store_stats(),
1596 {'x509_ca': 0, 'crl': 0, 'x509': 1})
Martin Panterb55f8b72016-01-14 12:53:56 +00001597 ctx.load_verify_locations(CAFILE_CACERT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001598 self.assertEqual(ctx.cert_store_stats(),
1599 {'x509_ca': 1, 'crl': 0, 'x509': 2})
1600
1601 def test_get_ca_certs(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001602 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001603 self.assertEqual(ctx.get_ca_certs(), [])
1604 # CERTFILE is not flagged as X509v3 Basic Constraints: CA:TRUE
1605 ctx.load_verify_locations(CERTFILE)
1606 self.assertEqual(ctx.get_ca_certs(), [])
Martin Panterb55f8b72016-01-14 12:53:56 +00001607 # but CAFILE_CACERT is a CA cert
1608 ctx.load_verify_locations(CAFILE_CACERT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001609 self.assertEqual(ctx.get_ca_certs(),
1610 [{'issuer': ((('organizationName', 'Root CA'),),
1611 (('organizationalUnitName', 'http://www.cacert.org'),),
1612 (('commonName', 'CA Cert Signing Authority'),),
1613 (('emailAddress', 'support@cacert.org'),)),
1614 'notAfter': asn1time('Mar 29 12:29:49 2033 GMT'),
1615 'notBefore': asn1time('Mar 30 12:29:49 2003 GMT'),
1616 'serialNumber': '00',
Christian Heimesbd3a7f92013-11-21 03:40:15 +01001617 'crlDistributionPoints': ('https://www.cacert.org/revoke.crl',),
Christian Heimes9a5395a2013-06-17 15:44:12 +02001618 'subject': ((('organizationName', 'Root CA'),),
1619 (('organizationalUnitName', 'http://www.cacert.org'),),
1620 (('commonName', 'CA Cert Signing Authority'),),
1621 (('emailAddress', 'support@cacert.org'),)),
1622 'version': 3}])
1623
Martin Panterb55f8b72016-01-14 12:53:56 +00001624 with open(CAFILE_CACERT) as f:
Christian Heimes9a5395a2013-06-17 15:44:12 +02001625 pem = f.read()
1626 der = ssl.PEM_cert_to_DER_cert(pem)
1627 self.assertEqual(ctx.get_ca_certs(True), [der])
1628
Christian Heimes72d28502013-11-23 13:56:58 +01001629 def test_load_default_certs(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001630 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001631 ctx.load_default_certs()
1632
Christian Heimesa170fa12017-09-15 20:27:30 +02001633 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001634 ctx.load_default_certs(ssl.Purpose.SERVER_AUTH)
1635 ctx.load_default_certs()
1636
Christian Heimesa170fa12017-09-15 20:27:30 +02001637 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001638 ctx.load_default_certs(ssl.Purpose.CLIENT_AUTH)
1639
Christian Heimesa170fa12017-09-15 20:27:30 +02001640 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001641 self.assertRaises(TypeError, ctx.load_default_certs, None)
1642 self.assertRaises(TypeError, ctx.load_default_certs, 'SERVER_AUTH')
1643
Benjamin Peterson91244e02014-10-03 18:17:15 -04001644 @unittest.skipIf(sys.platform == "win32", "not-Windows specific")
Christian Heimes598894f2016-09-05 23:19:05 +02001645 @unittest.skipIf(IS_LIBRESSL, "LibreSSL doesn't support env vars")
Benjamin Peterson5915b0f2014-10-03 17:27:05 -04001646 def test_load_default_certs_env(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001647 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Hai Shia7f5d932020-08-04 00:41:24 +08001648 with os_helper.EnvironmentVarGuard() as env:
Benjamin Peterson5915b0f2014-10-03 17:27:05 -04001649 env["SSL_CERT_DIR"] = CAPATH
1650 env["SSL_CERT_FILE"] = CERTFILE
1651 ctx.load_default_certs()
1652 self.assertEqual(ctx.cert_store_stats(), {"crl": 0, "x509": 1, "x509_ca": 0})
1653
Benjamin Peterson91244e02014-10-03 18:17:15 -04001654 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
Steve Dower68d663c2017-07-17 11:15:48 +02001655 @unittest.skipIf(hasattr(sys, "gettotalrefcount"), "Debug build does not share environment between CRTs")
Benjamin Peterson91244e02014-10-03 18:17:15 -04001656 def test_load_default_certs_env_windows(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001657 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Benjamin Peterson91244e02014-10-03 18:17:15 -04001658 ctx.load_default_certs()
1659 stats = ctx.cert_store_stats()
1660
Christian Heimesa170fa12017-09-15 20:27:30 +02001661 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Hai Shia7f5d932020-08-04 00:41:24 +08001662 with os_helper.EnvironmentVarGuard() as env:
Benjamin Peterson91244e02014-10-03 18:17:15 -04001663 env["SSL_CERT_DIR"] = CAPATH
1664 env["SSL_CERT_FILE"] = CERTFILE
1665 ctx.load_default_certs()
1666 stats["x509"] += 1
1667 self.assertEqual(ctx.cert_store_stats(), stats)
1668
Christian Heimes358cfd42016-09-10 22:43:48 +02001669 def _assert_context_options(self, ctx):
1670 self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
1671 if OP_NO_COMPRESSION != 0:
1672 self.assertEqual(ctx.options & OP_NO_COMPRESSION,
1673 OP_NO_COMPRESSION)
1674 if OP_SINGLE_DH_USE != 0:
1675 self.assertEqual(ctx.options & OP_SINGLE_DH_USE,
1676 OP_SINGLE_DH_USE)
1677 if OP_SINGLE_ECDH_USE != 0:
1678 self.assertEqual(ctx.options & OP_SINGLE_ECDH_USE,
1679 OP_SINGLE_ECDH_USE)
1680 if OP_CIPHER_SERVER_PREFERENCE != 0:
1681 self.assertEqual(ctx.options & OP_CIPHER_SERVER_PREFERENCE,
1682 OP_CIPHER_SERVER_PREFERENCE)
1683
Christian Heimes4c05b472013-11-23 15:58:30 +01001684 def test_create_default_context(self):
1685 ctx = ssl.create_default_context()
Christian Heimes358cfd42016-09-10 22:43:48 +02001686
Christian Heimesa170fa12017-09-15 20:27:30 +02001687 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
Christian Heimes4c05b472013-11-23 15:58:30 +01001688 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001689 self.assertTrue(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001690 self._assert_context_options(ctx)
1691
Christian Heimes4c05b472013-11-23 15:58:30 +01001692 with open(SIGNING_CA) as f:
1693 cadata = f.read()
1694 ctx = ssl.create_default_context(cafile=SIGNING_CA, capath=CAPATH,
1695 cadata=cadata)
Christian Heimesa170fa12017-09-15 20:27:30 +02001696 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
Christian Heimes4c05b472013-11-23 15:58:30 +01001697 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes358cfd42016-09-10 22:43:48 +02001698 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001699
1700 ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
Christian Heimesa170fa12017-09-15 20:27:30 +02001701 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
Christian Heimes4c05b472013-11-23 15:58:30 +01001702 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001703 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001704
Christian Heimes67986f92013-11-23 22:43:47 +01001705 def test__create_stdlib_context(self):
1706 ctx = ssl._create_stdlib_context()
Christian Heimesa170fa12017-09-15 20:27:30 +02001707 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
Christian Heimes67986f92013-11-23 22:43:47 +01001708 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001709 self.assertFalse(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001710 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001711
1712 ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1)
1713 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
1714 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001715 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001716
1717 ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1,
Christian Heimesa02c69a2013-12-02 20:59:28 +01001718 cert_reqs=ssl.CERT_REQUIRED,
1719 check_hostname=True)
Christian Heimes67986f92013-11-23 22:43:47 +01001720 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
1721 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimesa02c69a2013-12-02 20:59:28 +01001722 self.assertTrue(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001723 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001724
1725 ctx = ssl._create_stdlib_context(purpose=ssl.Purpose.CLIENT_AUTH)
Christian Heimesa170fa12017-09-15 20:27:30 +02001726 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
Christian Heimes67986f92013-11-23 22:43:47 +01001727 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001728 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001729
Christian Heimes1aa9a752013-12-02 02:41:19 +01001730 def test_check_hostname(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001731 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001732 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001733 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001734
Christian Heimese82c0342017-09-15 20:29:57 +02001735 # Auto set CERT_REQUIRED
1736 ctx.check_hostname = True
1737 self.assertTrue(ctx.check_hostname)
1738 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1739 ctx.check_hostname = False
Christian Heimes1aa9a752013-12-02 02:41:19 +01001740 ctx.verify_mode = ssl.CERT_REQUIRED
1741 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001742 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001743
Christian Heimese82c0342017-09-15 20:29:57 +02001744 # Changing verify_mode does not affect check_hostname
1745 ctx.check_hostname = False
1746 ctx.verify_mode = ssl.CERT_NONE
1747 ctx.check_hostname = False
1748 self.assertFalse(ctx.check_hostname)
1749 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1750 # Auto set
Christian Heimes1aa9a752013-12-02 02:41:19 +01001751 ctx.check_hostname = True
1752 self.assertTrue(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001753 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1754
1755 ctx.check_hostname = False
1756 ctx.verify_mode = ssl.CERT_OPTIONAL
1757 ctx.check_hostname = False
1758 self.assertFalse(ctx.check_hostname)
1759 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1760 # keep CERT_OPTIONAL
1761 ctx.check_hostname = True
1762 self.assertTrue(ctx.check_hostname)
1763 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001764
1765 # Cannot set CERT_NONE with check_hostname enabled
1766 with self.assertRaises(ValueError):
1767 ctx.verify_mode = ssl.CERT_NONE
1768 ctx.check_hostname = False
1769 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001770 ctx.verify_mode = ssl.CERT_NONE
1771 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001772
Christian Heimes5fe668c2016-09-12 00:01:11 +02001773 def test_context_client_server(self):
1774 # PROTOCOL_TLS_CLIENT has sane defaults
1775 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1776 self.assertTrue(ctx.check_hostname)
1777 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1778
1779 # PROTOCOL_TLS_SERVER has different but also sane defaults
1780 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1781 self.assertFalse(ctx.check_hostname)
1782 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1783
Christian Heimes4df60f12017-09-15 20:26:05 +02001784 def test_context_custom_class(self):
1785 class MySSLSocket(ssl.SSLSocket):
1786 pass
1787
1788 class MySSLObject(ssl.SSLObject):
1789 pass
1790
1791 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1792 ctx.sslsocket_class = MySSLSocket
1793 ctx.sslobject_class = MySSLObject
1794
1795 with ctx.wrap_socket(socket.socket(), server_side=True) as sock:
1796 self.assertIsInstance(sock, MySSLSocket)
1797 obj = ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO())
1798 self.assertIsInstance(obj, MySSLObject)
1799
Christian Heimes78c7d522019-06-03 21:00:10 +02001800 @unittest.skipUnless(IS_OPENSSL_1_1_1, "Test requires OpenSSL 1.1.1")
1801 def test_num_tickest(self):
1802 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1803 self.assertEqual(ctx.num_tickets, 2)
1804 ctx.num_tickets = 1
1805 self.assertEqual(ctx.num_tickets, 1)
1806 ctx.num_tickets = 0
1807 self.assertEqual(ctx.num_tickets, 0)
1808 with self.assertRaises(ValueError):
1809 ctx.num_tickets = -1
1810 with self.assertRaises(TypeError):
1811 ctx.num_tickets = None
1812
1813 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1814 self.assertEqual(ctx.num_tickets, 2)
1815 with self.assertRaises(ValueError):
1816 ctx.num_tickets = 1
1817
Antoine Pitrou152efa22010-05-16 18:19:27 +00001818
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001819class SSLErrorTests(unittest.TestCase):
1820
1821 def test_str(self):
1822 # The str() of a SSLError doesn't include the errno
1823 e = ssl.SSLError(1, "foo")
1824 self.assertEqual(str(e), "foo")
1825 self.assertEqual(e.errno, 1)
1826 # Same for a subclass
1827 e = ssl.SSLZeroReturnError(1, "foo")
1828 self.assertEqual(str(e), "foo")
1829 self.assertEqual(e.errno, 1)
1830
Paul Monsonf3550692019-06-19 13:09:54 -07001831 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001832 def test_lib_reason(self):
1833 # Test the library and reason attributes
Christian Heimesa170fa12017-09-15 20:27:30 +02001834 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001835 with self.assertRaises(ssl.SSLError) as cm:
1836 ctx.load_dh_params(CERTFILE)
1837 self.assertEqual(cm.exception.library, 'PEM')
1838 self.assertEqual(cm.exception.reason, 'NO_START_LINE')
1839 s = str(cm.exception)
1840 self.assertTrue(s.startswith("[PEM: NO_START_LINE] no start line"), s)
1841
1842 def test_subclass(self):
1843 # Check that the appropriate SSLError subclass is raised
1844 # (this only tests one of them)
Christian Heimesa170fa12017-09-15 20:27:30 +02001845 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1846 ctx.check_hostname = False
1847 ctx.verify_mode = ssl.CERT_NONE
Giampaolo Rodolaeb7e29f2019-04-09 00:34:02 +02001848 with socket.create_server(("127.0.0.1", 0)) as s:
1849 c = socket.create_connection(s.getsockname())
Antoine Pitroue1ceb502013-01-12 21:54:44 +01001850 c.setblocking(False)
1851 with ctx.wrap_socket(c, False, do_handshake_on_connect=False) as c:
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001852 with self.assertRaises(ssl.SSLWantReadError) as cm:
1853 c.do_handshake()
1854 s = str(cm.exception)
1855 self.assertTrue(s.startswith("The operation did not complete (read)"), s)
1856 # For compatibility
1857 self.assertEqual(cm.exception.errno, ssl.SSL_ERROR_WANT_READ)
1858
1859
Christian Heimes61d478c2018-01-27 15:51:38 +01001860 def test_bad_server_hostname(self):
1861 ctx = ssl.create_default_context()
1862 with self.assertRaises(ValueError):
1863 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1864 server_hostname="")
1865 with self.assertRaises(ValueError):
1866 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1867 server_hostname=".example.org")
Christian Heimesd02ac252018-03-25 12:36:13 +02001868 with self.assertRaises(TypeError):
1869 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1870 server_hostname="example.org\x00evil.com")
Christian Heimes61d478c2018-01-27 15:51:38 +01001871
1872
Antoine Pitroub1fdf472014-10-05 20:41:53 +02001873class MemoryBIOTests(unittest.TestCase):
1874
1875 def test_read_write(self):
1876 bio = ssl.MemoryBIO()
1877 bio.write(b'foo')
1878 self.assertEqual(bio.read(), b'foo')
1879 self.assertEqual(bio.read(), b'')
1880 bio.write(b'foo')
1881 bio.write(b'bar')
1882 self.assertEqual(bio.read(), b'foobar')
1883 self.assertEqual(bio.read(), b'')
1884 bio.write(b'baz')
1885 self.assertEqual(bio.read(2), b'ba')
1886 self.assertEqual(bio.read(1), b'z')
1887 self.assertEqual(bio.read(1), b'')
1888
1889 def test_eof(self):
1890 bio = ssl.MemoryBIO()
1891 self.assertFalse(bio.eof)
1892 self.assertEqual(bio.read(), b'')
1893 self.assertFalse(bio.eof)
1894 bio.write(b'foo')
1895 self.assertFalse(bio.eof)
1896 bio.write_eof()
1897 self.assertFalse(bio.eof)
1898 self.assertEqual(bio.read(2), b'fo')
1899 self.assertFalse(bio.eof)
1900 self.assertEqual(bio.read(1), b'o')
1901 self.assertTrue(bio.eof)
1902 self.assertEqual(bio.read(), b'')
1903 self.assertTrue(bio.eof)
1904
1905 def test_pending(self):
1906 bio = ssl.MemoryBIO()
1907 self.assertEqual(bio.pending, 0)
1908 bio.write(b'foo')
1909 self.assertEqual(bio.pending, 3)
1910 for i in range(3):
1911 bio.read(1)
1912 self.assertEqual(bio.pending, 3-i-1)
1913 for i in range(3):
1914 bio.write(b'x')
1915 self.assertEqual(bio.pending, i+1)
1916 bio.read()
1917 self.assertEqual(bio.pending, 0)
1918
1919 def test_buffer_types(self):
1920 bio = ssl.MemoryBIO()
1921 bio.write(b'foo')
1922 self.assertEqual(bio.read(), b'foo')
1923 bio.write(bytearray(b'bar'))
1924 self.assertEqual(bio.read(), b'bar')
1925 bio.write(memoryview(b'baz'))
1926 self.assertEqual(bio.read(), b'baz')
1927
1928 def test_error_types(self):
1929 bio = ssl.MemoryBIO()
1930 self.assertRaises(TypeError, bio.write, 'foo')
1931 self.assertRaises(TypeError, bio.write, None)
1932 self.assertRaises(TypeError, bio.write, True)
1933 self.assertRaises(TypeError, bio.write, 1)
1934
1935
Christian Heimes9d50ab52018-02-27 10:17:30 +01001936class SSLObjectTests(unittest.TestCase):
1937 def test_private_init(self):
1938 bio = ssl.MemoryBIO()
1939 with self.assertRaisesRegex(TypeError, "public constructor"):
1940 ssl.SSLObject(bio, bio)
1941
Nathaniel J. Smithc0da5822018-09-21 21:44:12 -07001942 def test_unwrap(self):
1943 client_ctx, server_ctx, hostname = testing_context()
1944 c_in = ssl.MemoryBIO()
1945 c_out = ssl.MemoryBIO()
1946 s_in = ssl.MemoryBIO()
1947 s_out = ssl.MemoryBIO()
1948 client = client_ctx.wrap_bio(c_in, c_out, server_hostname=hostname)
1949 server = server_ctx.wrap_bio(s_in, s_out, server_side=True)
1950
1951 # Loop on the handshake for a bit to get it settled
1952 for _ in range(5):
1953 try:
1954 client.do_handshake()
1955 except ssl.SSLWantReadError:
1956 pass
1957 if c_out.pending:
1958 s_in.write(c_out.read())
1959 try:
1960 server.do_handshake()
1961 except ssl.SSLWantReadError:
1962 pass
1963 if s_out.pending:
1964 c_in.write(s_out.read())
1965 # Now the handshakes should be complete (don't raise WantReadError)
1966 client.do_handshake()
1967 server.do_handshake()
1968
1969 # Now if we unwrap one side unilaterally, it should send close-notify
1970 # and raise WantReadError:
1971 with self.assertRaises(ssl.SSLWantReadError):
1972 client.unwrap()
1973
1974 # But server.unwrap() does not raise, because it reads the client's
1975 # close-notify:
1976 s_in.write(c_out.read())
1977 server.unwrap()
1978
1979 # And now that the client gets the server's close-notify, it doesn't
1980 # raise either.
1981 c_in.write(s_out.read())
1982 client.unwrap()
Christian Heimes9d50ab52018-02-27 10:17:30 +01001983
Martin Panter3840b2a2016-03-27 01:53:46 +00001984class SimpleBackgroundTests(unittest.TestCase):
Martin Panter3840b2a2016-03-27 01:53:46 +00001985 """Tests that connect to a simple server running in the background"""
1986
1987 def setUp(self):
1988 server = ThreadedEchoServer(SIGNED_CERTFILE)
1989 self.server_addr = (HOST, server.port)
1990 server.__enter__()
1991 self.addCleanup(server.__exit__, None, None, None)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001992
Antoine Pitrou480a1242010-04-28 21:37:09 +00001993 def test_connect(self):
Christian Heimesd0486372016-09-10 23:23:33 +02001994 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001995 cert_reqs=ssl.CERT_NONE) as s:
1996 s.connect(self.server_addr)
1997 self.assertEqual({}, s.getpeercert())
Christian Heimesa5d07652016-09-24 10:48:05 +02001998 self.assertFalse(s.server_side)
Antoine Pitrou350c7222010-09-09 13:31:46 +00001999
Martin Panter3840b2a2016-03-27 01:53:46 +00002000 # this should succeed because we specify the root cert
Christian Heimesd0486372016-09-10 23:23:33 +02002001 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002002 cert_reqs=ssl.CERT_REQUIRED,
2003 ca_certs=SIGNING_CA) as s:
2004 s.connect(self.server_addr)
2005 self.assertTrue(s.getpeercert())
Christian Heimesa5d07652016-09-24 10:48:05 +02002006 self.assertFalse(s.server_side)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002007
Martin Panter3840b2a2016-03-27 01:53:46 +00002008 def test_connect_fail(self):
2009 # This should fail because we have no verification certs. Connection
2010 # failure crashes ThreadedEchoServer, so run this in an independent
2011 # test method.
Christian Heimesd0486372016-09-10 23:23:33 +02002012 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002013 cert_reqs=ssl.CERT_REQUIRED)
2014 self.addCleanup(s.close)
2015 self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
2016 s.connect, self.server_addr)
Antoine Pitrou152efa22010-05-16 18:19:27 +00002017
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002018 def test_connect_ex(self):
2019 # Issue #11326: check connect_ex() implementation
Christian Heimesd0486372016-09-10 23:23:33 +02002020 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002021 cert_reqs=ssl.CERT_REQUIRED,
2022 ca_certs=SIGNING_CA)
2023 self.addCleanup(s.close)
2024 self.assertEqual(0, s.connect_ex(self.server_addr))
2025 self.assertTrue(s.getpeercert())
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002026
2027 def test_non_blocking_connect_ex(self):
2028 # Issue #11326: non-blocking connect_ex() should allow handshake
2029 # to proceed after the socket gets ready.
Christian Heimesd0486372016-09-10 23:23:33 +02002030 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002031 cert_reqs=ssl.CERT_REQUIRED,
2032 ca_certs=SIGNING_CA,
2033 do_handshake_on_connect=False)
2034 self.addCleanup(s.close)
2035 s.setblocking(False)
2036 rc = s.connect_ex(self.server_addr)
2037 # EWOULDBLOCK under Windows, EINPROGRESS elsewhere
2038 self.assertIn(rc, (0, errno.EINPROGRESS, errno.EWOULDBLOCK))
2039 # Wait for connect to finish
2040 select.select([], [s], [], 5.0)
2041 # Non-blocking handshake
2042 while True:
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002043 try:
Martin Panter3840b2a2016-03-27 01:53:46 +00002044 s.do_handshake()
2045 break
2046 except ssl.SSLWantReadError:
2047 select.select([s], [], [], 5.0)
2048 except ssl.SSLWantWriteError:
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002049 select.select([], [s], [], 5.0)
Martin Panter3840b2a2016-03-27 01:53:46 +00002050 # SSL established
2051 self.assertTrue(s.getpeercert())
Antoine Pitrou40f12ab2012-12-28 19:03:43 +01002052
Antoine Pitrou152efa22010-05-16 18:19:27 +00002053 def test_connect_with_context(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002054 # Same as test_connect, but with a separately created context
Christian Heimesa170fa12017-09-15 20:27:30 +02002055 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Martin Panter3840b2a2016-03-27 01:53:46 +00002056 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2057 s.connect(self.server_addr)
2058 self.assertEqual({}, s.getpeercert())
2059 # Same with a server hostname
2060 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2061 server_hostname="dummy") as s:
2062 s.connect(self.server_addr)
2063 ctx.verify_mode = ssl.CERT_REQUIRED
2064 # This should succeed because we specify the root cert
2065 ctx.load_verify_locations(SIGNING_CA)
2066 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2067 s.connect(self.server_addr)
2068 cert = s.getpeercert()
2069 self.assertTrue(cert)
2070
2071 def test_connect_with_context_fail(self):
2072 # This should fail because we have no verification certs. Connection
2073 # failure crashes ThreadedEchoServer, so run this in an independent
2074 # test method.
Christian Heimesa170fa12017-09-15 20:27:30 +02002075 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Martin Panter3840b2a2016-03-27 01:53:46 +00002076 ctx.verify_mode = ssl.CERT_REQUIRED
2077 s = ctx.wrap_socket(socket.socket(socket.AF_INET))
2078 self.addCleanup(s.close)
2079 self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
2080 s.connect, self.server_addr)
Antoine Pitrou152efa22010-05-16 18:19:27 +00002081
2082 def test_connect_capath(self):
2083 # Verify server certificates using the `capath` argument
Antoine Pitrou467f28d2010-05-16 19:22:44 +00002084 # NOTE: the subject hashing algorithm has been changed between
2085 # OpenSSL 0.9.8n and 1.0.0, as a result the capath directory must
2086 # contain both versions of each certificate (same content, different
Antoine Pitroud7e4c1c2010-05-17 14:13:10 +00002087 # filename) for this test to be portable across OpenSSL releases.
Christian Heimesa170fa12017-09-15 20:27:30 +02002088 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Martin Panter3840b2a2016-03-27 01:53:46 +00002089 ctx.verify_mode = ssl.CERT_REQUIRED
2090 ctx.load_verify_locations(capath=CAPATH)
2091 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2092 s.connect(self.server_addr)
2093 cert = s.getpeercert()
2094 self.assertTrue(cert)
Christian Heimes529525f2018-05-23 22:24:45 +02002095
Martin Panter3840b2a2016-03-27 01:53:46 +00002096 # Same with a bytes `capath` argument
Christian Heimesa170fa12017-09-15 20:27:30 +02002097 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Martin Panter3840b2a2016-03-27 01:53:46 +00002098 ctx.verify_mode = ssl.CERT_REQUIRED
2099 ctx.load_verify_locations(capath=BYTES_CAPATH)
2100 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2101 s.connect(self.server_addr)
2102 cert = s.getpeercert()
2103 self.assertTrue(cert)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002104
Christian Heimesefff7062013-11-21 03:35:02 +01002105 def test_connect_cadata(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002106 with open(SIGNING_CA) as f:
Christian Heimesefff7062013-11-21 03:35:02 +01002107 pem = f.read()
2108 der = ssl.PEM_cert_to_DER_cert(pem)
Christian Heimesa170fa12017-09-15 20:27:30 +02002109 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Martin Panter3840b2a2016-03-27 01:53:46 +00002110 ctx.verify_mode = ssl.CERT_REQUIRED
2111 ctx.load_verify_locations(cadata=pem)
2112 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2113 s.connect(self.server_addr)
2114 cert = s.getpeercert()
2115 self.assertTrue(cert)
Christian Heimesefff7062013-11-21 03:35:02 +01002116
Martin Panter3840b2a2016-03-27 01:53:46 +00002117 # same with DER
Christian Heimesa170fa12017-09-15 20:27:30 +02002118 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Martin Panter3840b2a2016-03-27 01:53:46 +00002119 ctx.verify_mode = ssl.CERT_REQUIRED
2120 ctx.load_verify_locations(cadata=der)
2121 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2122 s.connect(self.server_addr)
2123 cert = s.getpeercert()
2124 self.assertTrue(cert)
Christian Heimesefff7062013-11-21 03:35:02 +01002125
Antoine Pitroue3220242010-04-24 11:13:53 +00002126 @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
2127 def test_makefile_close(self):
2128 # Issue #5238: creating a file-like object with makefile() shouldn't
2129 # delay closing the underlying "real socket" (here tested with its
2130 # file descriptor, hence skipping the test under Windows).
Christian Heimesd0486372016-09-10 23:23:33 +02002131 ss = test_wrap_socket(socket.socket(socket.AF_INET))
Martin Panter3840b2a2016-03-27 01:53:46 +00002132 ss.connect(self.server_addr)
2133 fd = ss.fileno()
2134 f = ss.makefile()
2135 f.close()
2136 # The fd is still open
2137 os.read(fd, 0)
2138 # Closing the SSL socket should close the fd too
2139 ss.close()
2140 gc.collect()
2141 with self.assertRaises(OSError) as e:
Antoine Pitroue3220242010-04-24 11:13:53 +00002142 os.read(fd, 0)
Martin Panter3840b2a2016-03-27 01:53:46 +00002143 self.assertEqual(e.exception.errno, errno.EBADF)
Antoine Pitroue3220242010-04-24 11:13:53 +00002144
Antoine Pitrou480a1242010-04-28 21:37:09 +00002145 def test_non_blocking_handshake(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002146 s = socket.socket(socket.AF_INET)
2147 s.connect(self.server_addr)
2148 s.setblocking(False)
Christian Heimesd0486372016-09-10 23:23:33 +02002149 s = test_wrap_socket(s,
Martin Panter3840b2a2016-03-27 01:53:46 +00002150 cert_reqs=ssl.CERT_NONE,
2151 do_handshake_on_connect=False)
2152 self.addCleanup(s.close)
2153 count = 0
2154 while True:
2155 try:
2156 count += 1
2157 s.do_handshake()
2158 break
2159 except ssl.SSLWantReadError:
2160 select.select([s], [], [])
2161 except ssl.SSLWantWriteError:
2162 select.select([], [s], [])
2163 if support.verbose:
2164 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002165
Antoine Pitrou480a1242010-04-28 21:37:09 +00002166 def test_get_server_certificate(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002167 _test_get_server_certificate(self, *self.server_addr, cert=SIGNING_CA)
Antoine Pitrou5aefa662011-04-28 19:24:46 +02002168
Martin Panter3840b2a2016-03-27 01:53:46 +00002169 def test_get_server_certificate_fail(self):
2170 # Connection failure crashes ThreadedEchoServer, so run this in an
2171 # independent test method
2172 _test_get_server_certificate_fail(self, *self.server_addr)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002173
Antoine Pitrouf4c7bad2010-08-15 23:02:22 +00002174 def test_ciphers(self):
Christian Heimesd0486372016-09-10 23:23:33 +02002175 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002176 cert_reqs=ssl.CERT_NONE, ciphers="ALL") as s:
2177 s.connect(self.server_addr)
Christian Heimesd0486372016-09-10 23:23:33 +02002178 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002179 cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT") as s:
2180 s.connect(self.server_addr)
2181 # Error checking can happen at instantiation or when connecting
2182 with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
2183 with socket.socket(socket.AF_INET) as sock:
Christian Heimesd0486372016-09-10 23:23:33 +02002184 s = test_wrap_socket(sock,
Martin Panter3840b2a2016-03-27 01:53:46 +00002185 cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
2186 s.connect(self.server_addr)
Antoine Pitroufec12ff2010-04-21 19:46:23 +00002187
Christian Heimes9a5395a2013-06-17 15:44:12 +02002188 def test_get_ca_certs_capath(self):
2189 # capath certs are loaded on request
Christian Heimesa170fa12017-09-15 20:27:30 +02002190 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002191 ctx.load_verify_locations(capath=CAPATH)
2192 self.assertEqual(ctx.get_ca_certs(), [])
Christian Heimesa170fa12017-09-15 20:27:30 +02002193 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2194 server_hostname='localhost') as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002195 s.connect(self.server_addr)
2196 cert = s.getpeercert()
2197 self.assertTrue(cert)
2198 self.assertEqual(len(ctx.get_ca_certs()), 1)
Christian Heimes9a5395a2013-06-17 15:44:12 +02002199
Christian Heimes575596e2013-12-15 21:49:17 +01002200 @needs_sni
Christian Heimes8e7f3942013-12-05 07:41:08 +01002201 def test_context_setget(self):
2202 # Check that the context of a connected socket can be replaced.
Christian Heimesa170fa12017-09-15 20:27:30 +02002203 ctx1 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2204 ctx1.load_verify_locations(capath=CAPATH)
2205 ctx2 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2206 ctx2.load_verify_locations(capath=CAPATH)
Martin Panter3840b2a2016-03-27 01:53:46 +00002207 s = socket.socket(socket.AF_INET)
Christian Heimesa170fa12017-09-15 20:27:30 +02002208 with ctx1.wrap_socket(s, server_hostname='localhost') as ss:
Martin Panter3840b2a2016-03-27 01:53:46 +00002209 ss.connect(self.server_addr)
2210 self.assertIs(ss.context, ctx1)
2211 self.assertIs(ss._sslobj.context, ctx1)
2212 ss.context = ctx2
2213 self.assertIs(ss.context, ctx2)
2214 self.assertIs(ss._sslobj.context, ctx2)
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002215
2216 def ssl_io_loop(self, sock, incoming, outgoing, func, *args, **kwargs):
2217 # A simple IO loop. Call func(*args) depending on the error we get
2218 # (WANT_READ or WANT_WRITE) move data between the socket and the BIOs.
Victor Stinner0d63bac2019-12-11 11:30:03 +01002219 timeout = kwargs.get('timeout', support.SHORT_TIMEOUT)
Victor Stinner50a72af2017-09-11 09:34:24 -07002220 deadline = time.monotonic() + timeout
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002221 count = 0
2222 while True:
Victor Stinner50a72af2017-09-11 09:34:24 -07002223 if time.monotonic() > deadline:
2224 self.fail("timeout")
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002225 errno = None
2226 count += 1
2227 try:
2228 ret = func(*args)
2229 except ssl.SSLError as e:
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002230 if e.errno not in (ssl.SSL_ERROR_WANT_READ,
Martin Panter40b97ec2016-01-14 13:05:46 +00002231 ssl.SSL_ERROR_WANT_WRITE):
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002232 raise
2233 errno = e.errno
2234 # Get any data from the outgoing BIO irrespective of any error, and
2235 # send it to the socket.
2236 buf = outgoing.read()
2237 sock.sendall(buf)
2238 # If there's no error, we're done. For WANT_READ, we need to get
2239 # data from the socket and put it in the incoming BIO.
2240 if errno is None:
2241 break
2242 elif errno == ssl.SSL_ERROR_WANT_READ:
2243 buf = sock.recv(32768)
2244 if buf:
2245 incoming.write(buf)
2246 else:
2247 incoming.write_eof()
2248 if support.verbose:
2249 sys.stdout.write("Needed %d calls to complete %s().\n"
2250 % (count, func.__name__))
2251 return ret
2252
Martin Panter3840b2a2016-03-27 01:53:46 +00002253 def test_bio_handshake(self):
2254 sock = socket.socket(socket.AF_INET)
2255 self.addCleanup(sock.close)
2256 sock.connect(self.server_addr)
2257 incoming = ssl.MemoryBIO()
2258 outgoing = ssl.MemoryBIO()
Christian Heimesa170fa12017-09-15 20:27:30 +02002259 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2260 self.assertTrue(ctx.check_hostname)
2261 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Martin Panter3840b2a2016-03-27 01:53:46 +00002262 ctx.load_verify_locations(SIGNING_CA)
Christian Heimesa170fa12017-09-15 20:27:30 +02002263 sslobj = ctx.wrap_bio(incoming, outgoing, False,
2264 SIGNED_CERTFILE_HOSTNAME)
Martin Panter3840b2a2016-03-27 01:53:46 +00002265 self.assertIs(sslobj._sslobj.owner, sslobj)
2266 self.assertIsNone(sslobj.cipher())
Christian Heimes68771112017-09-05 21:55:40 -07002267 self.assertIsNone(sslobj.version())
Christian Heimes01113fa2016-09-05 23:23:24 +02002268 self.assertIsNotNone(sslobj.shared_ciphers())
Martin Panter3840b2a2016-03-27 01:53:46 +00002269 self.assertRaises(ValueError, sslobj.getpeercert)
2270 if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
2271 self.assertIsNone(sslobj.get_channel_binding('tls-unique'))
2272 self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
2273 self.assertTrue(sslobj.cipher())
Christian Heimes01113fa2016-09-05 23:23:24 +02002274 self.assertIsNotNone(sslobj.shared_ciphers())
Christian Heimes68771112017-09-05 21:55:40 -07002275 self.assertIsNotNone(sslobj.version())
Martin Panter3840b2a2016-03-27 01:53:46 +00002276 self.assertTrue(sslobj.getpeercert())
2277 if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
2278 self.assertTrue(sslobj.get_channel_binding('tls-unique'))
2279 try:
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002280 self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
Martin Panter3840b2a2016-03-27 01:53:46 +00002281 except ssl.SSLSyscallError:
2282 # If the server shuts down the TCP connection without sending a
2283 # secure shutdown message, this is reported as SSL_ERROR_SYSCALL
2284 pass
2285 self.assertRaises(ssl.SSLError, sslobj.write, b'foo')
2286
2287 def test_bio_read_write_data(self):
2288 sock = socket.socket(socket.AF_INET)
2289 self.addCleanup(sock.close)
2290 sock.connect(self.server_addr)
2291 incoming = ssl.MemoryBIO()
2292 outgoing = ssl.MemoryBIO()
Christian Heimesa170fa12017-09-15 20:27:30 +02002293 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Martin Panter3840b2a2016-03-27 01:53:46 +00002294 ctx.verify_mode = ssl.CERT_NONE
2295 sslobj = ctx.wrap_bio(incoming, outgoing, False)
2296 self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
2297 req = b'FOO\n'
2298 self.ssl_io_loop(sock, incoming, outgoing, sslobj.write, req)
2299 buf = self.ssl_io_loop(sock, incoming, outgoing, sslobj.read, 1024)
2300 self.assertEqual(buf, b'foo\n')
2301 self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002302
2303
Martin Panter3840b2a2016-03-27 01:53:46 +00002304class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002305
Martin Panter3840b2a2016-03-27 01:53:46 +00002306 def test_timeout_connect_ex(self):
2307 # Issue #12065: on a timeout, connect_ex() should return the original
2308 # errno (mimicking the behaviour of non-SSL sockets).
Serhiy Storchakabfb1cf42020-04-29 10:36:20 +03002309 with socket_helper.transient_internet(REMOTE_HOST):
Christian Heimesd0486372016-09-10 23:23:33 +02002310 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002311 cert_reqs=ssl.CERT_REQUIRED,
2312 do_handshake_on_connect=False)
2313 self.addCleanup(s.close)
2314 s.settimeout(0.0000001)
2315 rc = s.connect_ex((REMOTE_HOST, 443))
2316 if rc == 0:
2317 self.skipTest("REMOTE_HOST responded too quickly")
Carl Meyer29c451c2021-03-27 15:52:28 -06002318 elif rc == errno.ENETUNREACH:
2319 self.skipTest("Network unreachable.")
Martin Panter3840b2a2016-03-27 01:53:46 +00002320 self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK))
2321
Serhiy Storchaka16994912020-04-25 10:06:29 +03002322 @unittest.skipUnless(socket_helper.IPV6_ENABLED, 'Needs IPv6')
Martin Panter3840b2a2016-03-27 01:53:46 +00002323 def test_get_server_certificate_ipv6(self):
Serhiy Storchakabfb1cf42020-04-29 10:36:20 +03002324 with socket_helper.transient_internet('ipv6.google.com'):
Martin Panter3840b2a2016-03-27 01:53:46 +00002325 _test_get_server_certificate(self, 'ipv6.google.com', 443)
2326 _test_get_server_certificate_fail(self, 'ipv6.google.com', 443)
2327
Martin Panter3840b2a2016-03-27 01:53:46 +00002328
2329def _test_get_server_certificate(test, host, port, cert=None):
2330 pem = ssl.get_server_certificate((host, port))
2331 if not pem:
2332 test.fail("No server certificate on %s:%s!" % (host, port))
2333
2334 pem = ssl.get_server_certificate((host, port), ca_certs=cert)
2335 if not pem:
2336 test.fail("No server certificate on %s:%s!" % (host, port))
2337 if support.verbose:
2338 sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem))
2339
2340def _test_get_server_certificate_fail(test, host, port):
2341 try:
2342 pem = ssl.get_server_certificate((host, port), ca_certs=CERTFILE)
2343 except ssl.SSLError as x:
2344 #should fail
2345 if support.verbose:
2346 sys.stdout.write("%s\n" % x)
2347 else:
2348 test.fail("Got server certificate %s for %s:%s!" % (pem, host, port))
2349
2350
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002351from test.ssl_servers import make_https_server
Antoine Pitrou803e6d62010-10-13 10:36:15 +00002352
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002353class ThreadedEchoServer(threading.Thread):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002354
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002355 class ConnectionHandler(threading.Thread):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002356
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002357 """A mildly complicated class, because we want it to work both
2358 with and without the SSL wrapper around the socket connection, so
2359 that we can test the STARTTLS functionality."""
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002360
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002361 def __init__(self, server, connsock, addr):
2362 self.server = server
2363 self.running = False
2364 self.sock = connsock
2365 self.addr = addr
Serhiy Storchaka5eca7f32019-09-01 12:12:52 +03002366 self.sock.setblocking(True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002367 self.sslconn = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002368 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +00002369 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002370
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002371 def wrap_conn(self):
2372 try:
2373 self.sslconn = self.server.context.wrap_socket(
2374 self.sock, server_side=True)
2375 self.server.selected_npn_protocols.append(self.sslconn.selected_npn_protocol())
2376 self.server.selected_alpn_protocols.append(self.sslconn.selected_alpn_protocol())
Paul Monsonfb7e7502019-05-15 15:38:55 -07002377 except (ConnectionResetError, BrokenPipeError, ConnectionAbortedError) as e:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002378 # We treat ConnectionResetError as though it were an
2379 # SSLError - OpenSSL on Ubuntu abruptly closes the
2380 # connection when asked to use an unsupported protocol.
2381 #
Christian Heimes529525f2018-05-23 22:24:45 +02002382 # BrokenPipeError is raised in TLS 1.3 mode, when OpenSSL
2383 # tries to send session tickets after handshake.
2384 # https://github.com/openssl/openssl/issues/6342
Paul Monsonfb7e7502019-05-15 15:38:55 -07002385 #
2386 # ConnectionAbortedError is raised in TLS 1.3 mode, when OpenSSL
2387 # tries to send session tickets after handshake when using WinSock.
Christian Heimes529525f2018-05-23 22:24:45 +02002388 self.server.conn_errors.append(str(e))
2389 if self.server.chatty:
2390 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
2391 self.running = False
2392 self.close()
2393 return False
2394 except (ssl.SSLError, OSError) as e:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002395 # OSError may occur with wrong protocols, e.g. both
2396 # sides use PROTOCOL_TLS_SERVER.
2397 #
2398 # XXX Various errors can have happened here, for example
2399 # a mismatching protocol version, an invalid certificate,
2400 # or a low-level bug. This should be made more discriminating.
2401 #
2402 # bpo-31323: Store the exception as string to prevent
2403 # a reference leak: server -> conn_errors -> exception
2404 # -> traceback -> self (ConnectionHandler) -> server
2405 self.server.conn_errors.append(str(e))
2406 if self.server.chatty:
2407 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
2408 self.running = False
2409 self.server.stop()
2410 self.close()
2411 return False
2412 else:
2413 self.server.shared_ciphers.append(self.sslconn.shared_ciphers())
2414 if self.server.context.verify_mode == ssl.CERT_REQUIRED:
2415 cert = self.sslconn.getpeercert()
2416 if support.verbose and self.server.chatty:
2417 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
2418 cert_binary = self.sslconn.getpeercert(True)
2419 if support.verbose and self.server.chatty:
2420 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
2421 cipher = self.sslconn.cipher()
2422 if support.verbose and self.server.chatty:
2423 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
2424 sys.stdout.write(" server: selected protocol is now "
2425 + str(self.sslconn.selected_npn_protocol()) + "\n")
2426 return True
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002427
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002428 def read(self):
2429 if self.sslconn:
2430 return self.sslconn.read()
2431 else:
2432 return self.sock.recv(1024)
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002433
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002434 def write(self, bytes):
2435 if self.sslconn:
2436 return self.sslconn.write(bytes)
2437 else:
2438 return self.sock.send(bytes)
2439
2440 def close(self):
2441 if self.sslconn:
2442 self.sslconn.close()
2443 else:
2444 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002445
Antoine Pitrou480a1242010-04-28 21:37:09 +00002446 def run(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002447 self.running = True
2448 if not self.server.starttls_server:
2449 if not self.wrap_conn():
2450 return
2451 while self.running:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002452 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002453 msg = self.read()
2454 stripped = msg.strip()
2455 if not stripped:
2456 # eof, so quit this handler
2457 self.running = False
2458 try:
2459 self.sock = self.sslconn.unwrap()
2460 except OSError:
2461 # Many tests shut the TCP connection down
2462 # without an SSL shutdown. This causes
2463 # unwrap() to raise OSError with errno=0!
2464 pass
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00002465 else:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002466 self.sslconn = None
2467 self.close()
2468 elif stripped == b'over':
2469 if support.verbose and self.server.connectionchatty:
2470 sys.stdout.write(" server: client closed connection\n")
2471 self.close()
2472 return
2473 elif (self.server.starttls_server and
2474 stripped == b'STARTTLS'):
2475 if support.verbose and self.server.connectionchatty:
2476 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
2477 self.write(b"OK\n")
2478 if not self.wrap_conn():
2479 return
2480 elif (self.server.starttls_server and self.sslconn
2481 and stripped == b'ENDTLS'):
2482 if support.verbose and self.server.connectionchatty:
2483 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
2484 self.write(b"OK\n")
2485 self.sock = self.sslconn.unwrap()
2486 self.sslconn = None
2487 if support.verbose and self.server.connectionchatty:
2488 sys.stdout.write(" server: connection is now unencrypted...\n")
2489 elif stripped == b'CB tls-unique':
2490 if support.verbose and self.server.connectionchatty:
2491 sys.stdout.write(" server: read CB tls-unique from client, sending our CB data...\n")
2492 data = self.sslconn.get_channel_binding("tls-unique")
2493 self.write(repr(data).encode("us-ascii") + b"\n")
Christian Heimes9fb051f2018-09-23 08:32:31 +02002494 elif stripped == b'PHA':
2495 if support.verbose and self.server.connectionchatty:
2496 sys.stdout.write(" server: initiating post handshake auth\n")
2497 try:
2498 self.sslconn.verify_client_post_handshake()
2499 except ssl.SSLError as e:
2500 self.write(repr(e).encode("us-ascii") + b"\n")
2501 else:
2502 self.write(b"OK\n")
2503 elif stripped == b'HASCERT':
2504 if self.sslconn.getpeercert() is not None:
2505 self.write(b'TRUE\n')
2506 else:
2507 self.write(b'FALSE\n')
2508 elif stripped == b'GETCERT':
2509 cert = self.sslconn.getpeercert()
2510 self.write(repr(cert).encode("us-ascii") + b"\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002511 else:
2512 if (support.verbose and
2513 self.server.connectionchatty):
2514 ctype = (self.sslconn and "encrypted") or "unencrypted"
2515 sys.stdout.write(" server: read %r (%s), sending back %r (%s)...\n"
2516 % (msg, ctype, msg.lower(), ctype))
2517 self.write(msg.lower())
Paul Monsonfb7e7502019-05-15 15:38:55 -07002518 except (ConnectionResetError, ConnectionAbortedError):
Christian Heimes529525f2018-05-23 22:24:45 +02002519 # XXX: OpenSSL 1.1.1 sometimes raises ConnectionResetError
2520 # when connection is not shut down gracefully.
2521 if self.server.chatty and support.verbose:
2522 sys.stdout.write(
2523 " Connection reset by peer: {}\n".format(
2524 self.addr)
2525 )
2526 self.close()
2527 self.running = False
Paul Monsonfb7e7502019-05-15 15:38:55 -07002528 except ssl.SSLError as err:
2529 # On Windows sometimes test_pha_required_nocert receives the
2530 # PEER_DID_NOT_RETURN_A_CERTIFICATE exception
2531 # before the 'tlsv13 alert certificate required' exception.
2532 # If the server is stopped when PEER_DID_NOT_RETURN_A_CERTIFICATE
2533 # is received test_pha_required_nocert fails with ConnectionResetError
2534 # because the underlying socket is closed
2535 if 'PEER_DID_NOT_RETURN_A_CERTIFICATE' == err.reason:
2536 if self.server.chatty and support.verbose:
2537 sys.stdout.write(err.args[1])
2538 # test_pha_required_nocert is expecting this exception
2539 raise ssl.SSLError('tlsv13 alert certificate required')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002540 except OSError:
2541 if self.server.chatty:
2542 handle_error("Test server failure:\n")
Bill Janssen2f5799b2008-06-29 00:08:12 +00002543 self.close()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002544 self.running = False
Christian Heimes529525f2018-05-23 22:24:45 +02002545
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002546 # normally, we'd just stop here, but for the test
2547 # harness, we want to stop the server
2548 self.server.stop()
Bill Janssen54cc54c2007-12-14 22:08:56 +00002549
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002550 def __init__(self, certificate=None, ssl_version=None,
2551 certreqs=None, cacerts=None,
2552 chatty=True, connectionchatty=False, starttls_server=False,
2553 npn_protocols=None, alpn_protocols=None,
2554 ciphers=None, context=None):
2555 if context:
2556 self.context = context
2557 else:
2558 self.context = ssl.SSLContext(ssl_version
2559 if ssl_version is not None
Christian Heimesa170fa12017-09-15 20:27:30 +02002560 else ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002561 self.context.verify_mode = (certreqs if certreqs is not None
2562 else ssl.CERT_NONE)
2563 if cacerts:
2564 self.context.load_verify_locations(cacerts)
2565 if certificate:
2566 self.context.load_cert_chain(certificate)
2567 if npn_protocols:
2568 self.context.set_npn_protocols(npn_protocols)
2569 if alpn_protocols:
2570 self.context.set_alpn_protocols(alpn_protocols)
2571 if ciphers:
2572 self.context.set_ciphers(ciphers)
2573 self.chatty = chatty
2574 self.connectionchatty = connectionchatty
2575 self.starttls_server = starttls_server
2576 self.sock = socket.socket()
Serhiy Storchaka16994912020-04-25 10:06:29 +03002577 self.port = socket_helper.bind_port(self.sock)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002578 self.flag = None
2579 self.active = False
2580 self.selected_npn_protocols = []
2581 self.selected_alpn_protocols = []
2582 self.shared_ciphers = []
2583 self.conn_errors = []
2584 threading.Thread.__init__(self)
2585 self.daemon = True
2586
2587 def __enter__(self):
2588 self.start(threading.Event())
2589 self.flag.wait()
2590 return self
2591
2592 def __exit__(self, *args):
2593 self.stop()
2594 self.join()
2595
2596 def start(self, flag=None):
2597 self.flag = flag
2598 threading.Thread.start(self)
2599
2600 def run(self):
2601 self.sock.settimeout(0.05)
2602 self.sock.listen()
2603 self.active = True
2604 if self.flag:
2605 # signal an event
2606 self.flag.set()
2607 while self.active:
2608 try:
2609 newconn, connaddr = self.sock.accept()
2610 if support.verbose and self.chatty:
2611 sys.stdout.write(' server: new connection from '
2612 + repr(connaddr) + '\n')
2613 handler = self.ConnectionHandler(self, newconn, connaddr)
2614 handler.start()
2615 handler.join()
Christian Heimes03c8ddd2020-11-20 09:26:07 +01002616 except TimeoutError:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002617 pass
2618 except KeyboardInterrupt:
2619 self.stop()
Christian Heimes529525f2018-05-23 22:24:45 +02002620 except BaseException as e:
2621 if support.verbose and self.chatty:
2622 sys.stdout.write(
2623 ' connection handling failed: ' + repr(e) + '\n')
2624
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002625 self.sock.close()
2626
2627 def stop(self):
2628 self.active = False
2629
2630class AsyncoreEchoServer(threading.Thread):
2631
2632 # this one's based on asyncore.dispatcher
2633
2634 class EchoServer (asyncore.dispatcher):
2635
2636 class ConnectionHandler(asyncore.dispatcher_with_send):
2637
2638 def __init__(self, conn, certfile):
2639 self.socket = test_wrap_socket(conn, server_side=True,
2640 certfile=certfile,
2641 do_handshake_on_connect=False)
2642 asyncore.dispatcher_with_send.__init__(self, self.socket)
2643 self._ssl_accepting = True
2644 self._do_ssl_handshake()
2645
2646 def readable(self):
2647 if isinstance(self.socket, ssl.SSLSocket):
2648 while self.socket.pending() > 0:
2649 self.handle_read_event()
2650 return True
2651
2652 def _do_ssl_handshake(self):
2653 try:
2654 self.socket.do_handshake()
2655 except (ssl.SSLWantReadError, ssl.SSLWantWriteError):
2656 return
2657 except ssl.SSLEOFError:
2658 return self.handle_close()
2659 except ssl.SSLError:
Bill Janssen54cc54c2007-12-14 22:08:56 +00002660 raise
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002661 except OSError as err:
2662 if err.args[0] == errno.ECONNABORTED:
2663 return self.handle_close()
2664 else:
2665 self._ssl_accepting = False
Bill Janssen54cc54c2007-12-14 22:08:56 +00002666
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002667 def handle_read(self):
2668 if self._ssl_accepting:
2669 self._do_ssl_handshake()
2670 else:
2671 data = self.recv(1024)
2672 if support.verbose:
2673 sys.stdout.write(" server: read %s from client\n" % repr(data))
2674 if not data:
2675 self.close()
2676 else:
2677 self.send(data.lower())
Bill Janssen54cc54c2007-12-14 22:08:56 +00002678
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002679 def handle_close(self):
2680 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002681 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002682 sys.stdout.write(" server: closed connection %s\n" % self.socket)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002683
2684 def handle_error(self):
2685 raise
2686
Trent Nelson78520002008-04-10 20:54:35 +00002687 def __init__(self, certfile):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002688 self.certfile = certfile
2689 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Serhiy Storchaka16994912020-04-25 10:06:29 +03002690 self.port = socket_helper.bind_port(sock, '')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002691 asyncore.dispatcher.__init__(self, sock)
2692 self.listen(5)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002693
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002694 def handle_accepted(self, sock_obj, addr):
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002695 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002696 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
2697 self.ConnectionHandler(sock_obj, self.certfile)
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002698
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002699 def handle_error(self):
2700 raise
Bill Janssen54cc54c2007-12-14 22:08:56 +00002701
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002702 def __init__(self, certfile):
2703 self.flag = None
2704 self.active = False
2705 self.server = self.EchoServer(certfile)
2706 self.port = self.server.port
2707 threading.Thread.__init__(self)
2708 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +00002709
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002710 def __str__(self):
2711 return "<%s %s>" % (self.__class__.__name__, self.server)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002712
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002713 def __enter__(self):
2714 self.start(threading.Event())
2715 self.flag.wait()
2716 return self
Thomas Woutersed03b412007-08-28 21:37:11 +00002717
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002718 def __exit__(self, *args):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002719 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002720 sys.stdout.write(" cleanup: stopping server.\n")
2721 self.stop()
2722 if support.verbose:
2723 sys.stdout.write(" cleanup: joining server thread.\n")
2724 self.join()
2725 if support.verbose:
2726 sys.stdout.write(" cleanup: successfully joined.\n")
2727 # make sure that ConnectionHandler is removed from socket_map
2728 asyncore.close_all(ignore_all=True)
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01002729
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002730 def start (self, flag=None):
2731 self.flag = flag
2732 threading.Thread.start(self)
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01002733
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002734 def run(self):
2735 self.active = True
2736 if self.flag:
2737 self.flag.set()
2738 while self.active:
Antoine Pitrou773b5db2010-04-27 08:53:36 +00002739 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002740 asyncore.loop(1)
2741 except:
2742 pass
Trent Nelson6b240cd2008-04-10 20:12:06 +00002743
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002744 def stop(self):
2745 self.active = False
2746 self.server.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002747
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002748def server_params_test(client_context, server_context, indata=b"FOO\n",
2749 chatty=True, connectionchatty=False, sni_name=None,
2750 session=None):
2751 """
2752 Launch a server, connect a client to it and try various reads
2753 and writes.
2754 """
2755 stats = {}
2756 server = ThreadedEchoServer(context=server_context,
2757 chatty=chatty,
2758 connectionchatty=False)
2759 with server:
2760 with client_context.wrap_socket(socket.socket(),
2761 server_hostname=sni_name, session=session) as s:
2762 s.connect((HOST, server.port))
2763 for arg in [indata, bytearray(indata), memoryview(indata)]:
2764 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002765 if support.verbose:
Antoine Pitrou18c913e2010-04-27 10:59:39 +00002766 sys.stdout.write(
Antoine Pitrou480a1242010-04-28 21:37:09 +00002767 " client: sending %r...\n" % indata)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002768 s.write(arg)
Antoine Pitrou18c913e2010-04-27 10:59:39 +00002769 outdata = s.read()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002770 if connectionchatty:
2771 if support.verbose:
2772 sys.stdout.write(" client: read %r\n" % outdata)
Trent Nelson6b240cd2008-04-10 20:12:06 +00002773 if outdata != indata.lower():
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002774 raise AssertionError(
Antoine Pitrou480a1242010-04-28 21:37:09 +00002775 "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
2776 % (outdata[:20], len(outdata),
2777 indata[:20].lower(), len(indata)))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002778 s.write(b"over\n")
2779 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002780 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00002781 sys.stdout.write(" client: closing connection.\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002782 stats.update({
2783 'compression': s.compression(),
2784 'cipher': s.cipher(),
2785 'peercert': s.getpeercert(),
2786 'client_alpn_protocol': s.selected_alpn_protocol(),
2787 'client_npn_protocol': s.selected_npn_protocol(),
2788 'version': s.version(),
2789 'session_reused': s.session_reused,
2790 'session': s.session,
2791 })
2792 s.close()
2793 stats['server_alpn_protocols'] = server.selected_alpn_protocols
2794 stats['server_npn_protocols'] = server.selected_npn_protocols
2795 stats['server_shared_ciphers'] = server.shared_ciphers
2796 return stats
Trent Nelson6b240cd2008-04-10 20:12:06 +00002797
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002798def try_protocol_combo(server_protocol, client_protocol, expect_success,
2799 certsreqs=None, server_options=0, client_options=0):
2800 """
2801 Try to SSL-connect using *client_protocol* to *server_protocol*.
2802 If *expect_success* is true, assert that the connection succeeds,
2803 if it's false, assert that the connection fails.
2804 Also, if *expect_success* is a string, assert that it is the protocol
2805 version actually used by the connection.
2806 """
2807 if certsreqs is None:
2808 certsreqs = ssl.CERT_NONE
2809 certtype = {
2810 ssl.CERT_NONE: "CERT_NONE",
2811 ssl.CERT_OPTIONAL: "CERT_OPTIONAL",
2812 ssl.CERT_REQUIRED: "CERT_REQUIRED",
2813 }[certsreqs]
2814 if support.verbose:
2815 formatstr = (expect_success and " %s->%s %s\n") or " {%s->%s} %s\n"
2816 sys.stdout.write(formatstr %
2817 (ssl.get_protocol_name(client_protocol),
2818 ssl.get_protocol_name(server_protocol),
2819 certtype))
2820 client_context = ssl.SSLContext(client_protocol)
2821 client_context.options |= client_options
2822 server_context = ssl.SSLContext(server_protocol)
2823 server_context.options |= server_options
2824
Victor Stinner3ef63442019-02-19 18:06:03 +01002825 min_version = PROTOCOL_TO_TLS_VERSION.get(client_protocol, None)
2826 if (min_version is not None
2827 # SSLContext.minimum_version is only available on recent OpenSSL
2828 # (setter added in OpenSSL 1.1.0, getter added in OpenSSL 1.1.1)
2829 and hasattr(server_context, 'minimum_version')
2830 and server_protocol == ssl.PROTOCOL_TLS
2831 and server_context.minimum_version > min_version):
2832 # If OpenSSL configuration is strict and requires more recent TLS
2833 # version, we have to change the minimum to test old TLS versions.
2834 server_context.minimum_version = min_version
2835
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002836 # NOTE: we must enable "ALL" ciphers on the client, otherwise an
2837 # SSLv23 client will send an SSLv3 hello (rather than SSLv2)
2838 # starting from OpenSSL 1.0.0 (see issue #8322).
Christian Heimesa170fa12017-09-15 20:27:30 +02002839 if client_context.protocol == ssl.PROTOCOL_TLS:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002840 client_context.set_ciphers("ALL")
2841
Christian Heimesf6c6b582021-03-18 23:06:50 +01002842 seclevel_workaround(server_context, client_context)
2843
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002844 for ctx in (client_context, server_context):
2845 ctx.verify_mode = certsreqs
Christian Heimesbd5c7d22018-01-20 15:16:30 +01002846 ctx.load_cert_chain(SIGNED_CERTFILE)
2847 ctx.load_verify_locations(SIGNING_CA)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002848 try:
2849 stats = server_params_test(client_context, server_context,
2850 chatty=False, connectionchatty=False)
2851 # Protocol mismatch can result in either an SSLError, or a
2852 # "Connection reset by peer" error.
2853 except ssl.SSLError:
2854 if expect_success:
2855 raise
2856 except OSError as e:
2857 if expect_success or e.errno != errno.ECONNRESET:
2858 raise
2859 else:
2860 if not expect_success:
2861 raise AssertionError(
2862 "Client protocol %s succeeded with server protocol %s!"
2863 % (ssl.get_protocol_name(client_protocol),
2864 ssl.get_protocol_name(server_protocol)))
2865 elif (expect_success is not True
2866 and expect_success != stats['version']):
2867 raise AssertionError("version mismatch: expected %r, got %r"
2868 % (expect_success, stats['version']))
2869
2870
2871class ThreadedTests(unittest.TestCase):
2872
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002873 def test_echo(self):
2874 """Basic test of an SSL client connecting to a server"""
2875 if support.verbose:
2876 sys.stdout.write("\n")
2877 for protocol in PROTOCOLS:
2878 if protocol in {ssl.PROTOCOL_TLS_CLIENT, ssl.PROTOCOL_TLS_SERVER}:
2879 continue
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02002880 if not has_tls_protocol(protocol):
2881 continue
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002882 with self.subTest(protocol=ssl._PROTOCOL_NAMES[protocol]):
2883 context = ssl.SSLContext(protocol)
2884 context.load_cert_chain(CERTFILE)
Christian Heimesf6c6b582021-03-18 23:06:50 +01002885 seclevel_workaround(context)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002886 server_params_test(context, context,
2887 chatty=True, connectionchatty=True)
2888
Christian Heimesa170fa12017-09-15 20:27:30 +02002889 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002890
2891 with self.subTest(client=ssl.PROTOCOL_TLS_CLIENT, server=ssl.PROTOCOL_TLS_SERVER):
2892 server_params_test(client_context=client_context,
2893 server_context=server_context,
2894 chatty=True, connectionchatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02002895 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002896
2897 client_context.check_hostname = False
2898 with self.subTest(client=ssl.PROTOCOL_TLS_SERVER, server=ssl.PROTOCOL_TLS_CLIENT):
2899 with self.assertRaises(ssl.SSLError) as e:
2900 server_params_test(client_context=server_context,
2901 server_context=client_context,
2902 chatty=True, connectionchatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02002903 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002904 self.assertIn('called a function you should not call',
2905 str(e.exception))
2906
2907 with self.subTest(client=ssl.PROTOCOL_TLS_SERVER, server=ssl.PROTOCOL_TLS_SERVER):
2908 with self.assertRaises(ssl.SSLError) as e:
2909 server_params_test(client_context=server_context,
2910 server_context=server_context,
2911 chatty=True, connectionchatty=True)
2912 self.assertIn('called a function you should not call',
2913 str(e.exception))
2914
2915 with self.subTest(client=ssl.PROTOCOL_TLS_CLIENT, server=ssl.PROTOCOL_TLS_CLIENT):
2916 with self.assertRaises(ssl.SSLError) as e:
2917 server_params_test(client_context=server_context,
2918 server_context=client_context,
2919 chatty=True, connectionchatty=True)
2920 self.assertIn('called a function you should not call',
2921 str(e.exception))
2922
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002923 def test_getpeercert(self):
2924 if support.verbose:
2925 sys.stdout.write("\n")
Christian Heimesa170fa12017-09-15 20:27:30 +02002926
2927 client_context, server_context, hostname = testing_context()
2928 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002929 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002930 with client_context.wrap_socket(socket.socket(),
2931 do_handshake_on_connect=False,
2932 server_hostname=hostname) as s:
2933 s.connect((HOST, server.port))
2934 # getpeercert() raise ValueError while the handshake isn't
2935 # done.
2936 with self.assertRaises(ValueError):
2937 s.getpeercert()
2938 s.do_handshake()
2939 cert = s.getpeercert()
2940 self.assertTrue(cert, "Can't get peer certificate.")
2941 cipher = s.cipher()
2942 if support.verbose:
2943 sys.stdout.write(pprint.pformat(cert) + '\n')
2944 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
2945 if 'subject' not in cert:
2946 self.fail("No subject field in certificate: %s." %
2947 pprint.pformat(cert))
2948 if ((('organizationName', 'Python Software Foundation'),)
2949 not in cert['subject']):
2950 self.fail(
2951 "Missing or invalid 'organizationName' field in certificate subject; "
2952 "should be 'Python Software Foundation'.")
2953 self.assertIn('notBefore', cert)
2954 self.assertIn('notAfter', cert)
2955 before = ssl.cert_time_to_seconds(cert['notBefore'])
2956 after = ssl.cert_time_to_seconds(cert['notAfter'])
2957 self.assertLess(before, after)
Bill Janssen58afe4c2008-09-08 16:45:19 +00002958
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002959 @unittest.skipUnless(have_verify_flags(),
2960 "verify_flags need OpenSSL > 0.9.8")
2961 def test_crl_check(self):
2962 if support.verbose:
2963 sys.stdout.write("\n")
2964
Christian Heimesa170fa12017-09-15 20:27:30 +02002965 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002966
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002967 tf = getattr(ssl, "VERIFY_X509_TRUSTED_FIRST", 0)
Christian Heimesa170fa12017-09-15 20:27:30 +02002968 self.assertEqual(client_context.verify_flags, ssl.VERIFY_DEFAULT | tf)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002969
2970 # VERIFY_DEFAULT should pass
2971 server = ThreadedEchoServer(context=server_context, chatty=True)
2972 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002973 with client_context.wrap_socket(socket.socket(),
2974 server_hostname=hostname) as s:
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002975 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002976 cert = s.getpeercert()
2977 self.assertTrue(cert, "Can't get peer certificate.")
Bill Janssen58afe4c2008-09-08 16:45:19 +00002978
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002979 # VERIFY_CRL_CHECK_LEAF without a loaded CRL file fails
Christian Heimesa170fa12017-09-15 20:27:30 +02002980 client_context.verify_flags |= ssl.VERIFY_CRL_CHECK_LEAF
Bill Janssen58afe4c2008-09-08 16:45:19 +00002981
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002982 server = ThreadedEchoServer(context=server_context, chatty=True)
2983 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002984 with client_context.wrap_socket(socket.socket(),
2985 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002986 with self.assertRaisesRegex(ssl.SSLError,
2987 "certificate verify failed"):
2988 s.connect((HOST, server.port))
Bill Janssen58afe4c2008-09-08 16:45:19 +00002989
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002990 # now load a CRL file. The CRL file is signed by the CA.
Christian Heimesa170fa12017-09-15 20:27:30 +02002991 client_context.load_verify_locations(CRLFILE)
Bill Janssen58afe4c2008-09-08 16:45:19 +00002992
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002993 server = ThreadedEchoServer(context=server_context, chatty=True)
2994 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002995 with client_context.wrap_socket(socket.socket(),
2996 server_hostname=hostname) as s:
Antoine Pitroub4bebda2014-04-29 10:03:28 +02002997 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002998 cert = s.getpeercert()
2999 self.assertTrue(cert, "Can't get peer certificate.")
Antoine Pitroub4bebda2014-04-29 10:03:28 +02003000
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003001 def test_check_hostname(self):
3002 if support.verbose:
3003 sys.stdout.write("\n")
Antoine Pitroub4bebda2014-04-29 10:03:28 +02003004
Christian Heimesa170fa12017-09-15 20:27:30 +02003005 client_context, server_context, hostname = testing_context()
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003006
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003007 # correct hostname should verify
3008 server = ThreadedEchoServer(context=server_context, chatty=True)
3009 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02003010 with client_context.wrap_socket(socket.socket(),
3011 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003012 s.connect((HOST, server.port))
3013 cert = s.getpeercert()
3014 self.assertTrue(cert, "Can't get peer certificate.")
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003015
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003016 # incorrect hostname should raise an exception
3017 server = ThreadedEchoServer(context=server_context, chatty=True)
3018 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02003019 with client_context.wrap_socket(socket.socket(),
3020 server_hostname="invalid") as s:
Christian Heimes61d478c2018-01-27 15:51:38 +01003021 with self.assertRaisesRegex(
3022 ssl.CertificateError,
3023 "Hostname mismatch, certificate is not valid for 'invalid'."):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003024 s.connect((HOST, server.port))
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003025
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003026 # missing server_hostname arg should cause an exception, too
3027 server = ThreadedEchoServer(context=server_context, chatty=True)
3028 with server:
3029 with socket.socket() as s:
3030 with self.assertRaisesRegex(ValueError,
3031 "check_hostname requires server_hostname"):
Christian Heimesa170fa12017-09-15 20:27:30 +02003032 client_context.wrap_socket(s)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003033
Christian Heimesb467d9a2021-04-17 10:07:19 +02003034 @unittest.skipUnless(
3035 ssl.HAS_NEVER_CHECK_COMMON_NAME, "test requires hostname_checks_common_name"
3036 )
3037 def test_hostname_checks_common_name(self):
3038 client_context, server_context, hostname = testing_context()
3039 assert client_context.hostname_checks_common_name
3040 client_context.hostname_checks_common_name = False
3041
3042 # default cert has a SAN
3043 server = ThreadedEchoServer(context=server_context, chatty=True)
3044 with server:
3045 with client_context.wrap_socket(socket.socket(),
3046 server_hostname=hostname) as s:
3047 s.connect((HOST, server.port))
3048
3049 client_context, server_context, hostname = testing_context(NOSANFILE)
3050 client_context.hostname_checks_common_name = False
3051 server = ThreadedEchoServer(context=server_context, chatty=True)
3052 with server:
3053 with client_context.wrap_socket(socket.socket(),
3054 server_hostname=hostname) as s:
3055 with self.assertRaises(ssl.SSLCertVerificationError):
3056 s.connect((HOST, server.port))
3057
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003058 def test_ecc_cert(self):
3059 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3060 client_context.load_verify_locations(SIGNING_CA)
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003061 client_context.set_ciphers('ECDHE:ECDSA:!NULL:!aRSA')
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003062 hostname = SIGNED_CERTFILE_ECC_HOSTNAME
3063
3064 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3065 # load ECC cert
3066 server_context.load_cert_chain(SIGNED_CERTFILE_ECC)
3067
3068 # correct hostname should verify
3069 server = ThreadedEchoServer(context=server_context, chatty=True)
3070 with server:
3071 with client_context.wrap_socket(socket.socket(),
3072 server_hostname=hostname) as s:
3073 s.connect((HOST, server.port))
3074 cert = s.getpeercert()
3075 self.assertTrue(cert, "Can't get peer certificate.")
3076 cipher = s.cipher()[0].split('-')
3077 self.assertTrue(cipher[:2], ('ECDHE', 'ECDSA'))
3078
3079 def test_dual_rsa_ecc(self):
3080 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3081 client_context.load_verify_locations(SIGNING_CA)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003082 # TODO: fix TLSv1.3 once SSLContext can restrict signature
3083 # algorithms.
3084 client_context.options |= ssl.OP_NO_TLSv1_3
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003085 # only ECDSA certs
3086 client_context.set_ciphers('ECDHE:ECDSA:!NULL:!aRSA')
3087 hostname = SIGNED_CERTFILE_ECC_HOSTNAME
3088
3089 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3090 # load ECC and RSA key/cert pairs
3091 server_context.load_cert_chain(SIGNED_CERTFILE_ECC)
3092 server_context.load_cert_chain(SIGNED_CERTFILE)
3093
3094 # correct hostname should verify
3095 server = ThreadedEchoServer(context=server_context, chatty=True)
3096 with server:
3097 with client_context.wrap_socket(socket.socket(),
3098 server_hostname=hostname) as s:
3099 s.connect((HOST, server.port))
3100 cert = s.getpeercert()
3101 self.assertTrue(cert, "Can't get peer certificate.")
3102 cipher = s.cipher()[0].split('-')
3103 self.assertTrue(cipher[:2], ('ECDHE', 'ECDSA'))
3104
Christian Heimes66e57422018-01-29 14:25:13 +01003105 def test_check_hostname_idn(self):
3106 if support.verbose:
3107 sys.stdout.write("\n")
3108
Christian Heimes11a14932018-02-24 02:35:08 +01003109 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimes66e57422018-01-29 14:25:13 +01003110 server_context.load_cert_chain(IDNSANSFILE)
3111
Christian Heimes11a14932018-02-24 02:35:08 +01003112 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes66e57422018-01-29 14:25:13 +01003113 context.verify_mode = ssl.CERT_REQUIRED
3114 context.check_hostname = True
3115 context.load_verify_locations(SIGNING_CA)
3116
3117 # correct hostname should verify, when specified in several
3118 # different ways
3119 idn_hostnames = [
3120 ('könig.idn.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003121 'xn--knig-5qa.idn.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003122 ('xn--knig-5qa.idn.pythontest.net',
3123 'xn--knig-5qa.idn.pythontest.net'),
3124 (b'xn--knig-5qa.idn.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003125 'xn--knig-5qa.idn.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003126
3127 ('königsgäßchen.idna2003.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003128 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003129 ('xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
3130 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
3131 (b'xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003132 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
3133
3134 # ('königsgäßchen.idna2008.pythontest.net',
3135 # 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3136 ('xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
3137 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3138 (b'xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
3139 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3140
Christian Heimes66e57422018-01-29 14:25:13 +01003141 ]
3142 for server_hostname, expected_hostname in idn_hostnames:
3143 server = ThreadedEchoServer(context=server_context, chatty=True)
3144 with server:
3145 with context.wrap_socket(socket.socket(),
3146 server_hostname=server_hostname) as s:
3147 self.assertEqual(s.server_hostname, expected_hostname)
3148 s.connect((HOST, server.port))
3149 cert = s.getpeercert()
3150 self.assertEqual(s.server_hostname, expected_hostname)
3151 self.assertTrue(cert, "Can't get peer certificate.")
3152
Christian Heimes66e57422018-01-29 14:25:13 +01003153 # incorrect hostname should raise an exception
3154 server = ThreadedEchoServer(context=server_context, chatty=True)
3155 with server:
3156 with context.wrap_socket(socket.socket(),
3157 server_hostname="python.example.org") as s:
3158 with self.assertRaises(ssl.CertificateError):
3159 s.connect((HOST, server.port))
3160
Christian Heimes529525f2018-05-23 22:24:45 +02003161 def test_wrong_cert_tls12(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003162 """Connecting when the server rejects the client's certificate
3163
3164 Launch a server with CERT_REQUIRED, and check that trying to
3165 connect to it with a wrong client certificate fails.
3166 """
Christian Heimes05d9fe32018-02-27 08:55:39 +01003167 client_context, server_context, hostname = testing_context()
Christian Heimes88bfd0b2018-08-14 12:54:19 +02003168 # load client cert that is not signed by trusted CA
3169 client_context.load_cert_chain(CERTFILE)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003170 # require TLS client authentication
3171 server_context.verify_mode = ssl.CERT_REQUIRED
Christian Heimes529525f2018-05-23 22:24:45 +02003172 # TLS 1.3 has different handshake
3173 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimes05d9fe32018-02-27 08:55:39 +01003174
3175 server = ThreadedEchoServer(
3176 context=server_context, chatty=True, connectionchatty=True,
3177 )
3178
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003179 with server, \
Christian Heimes05d9fe32018-02-27 08:55:39 +01003180 client_context.wrap_socket(socket.socket(),
3181 server_hostname=hostname) as s:
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003182 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003183 # Expect either an SSL error about the server rejecting
3184 # the connection, or a low-level connection reset (which
3185 # sometimes happens on Windows)
3186 s.connect((HOST, server.port))
3187 except ssl.SSLError as e:
3188 if support.verbose:
3189 sys.stdout.write("\nSSLError is %r\n" % e)
3190 except OSError as e:
3191 if e.errno != errno.ECONNRESET:
3192 raise
3193 if support.verbose:
3194 sys.stdout.write("\nsocket.error is %r\n" % e)
3195 else:
3196 self.fail("Use of invalid cert should have failed!")
3197
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003198 @requires_tls_version('TLSv1_3')
Christian Heimes529525f2018-05-23 22:24:45 +02003199 def test_wrong_cert_tls13(self):
3200 client_context, server_context, hostname = testing_context()
Christian Heimes88bfd0b2018-08-14 12:54:19 +02003201 # load client cert that is not signed by trusted CA
3202 client_context.load_cert_chain(CERTFILE)
Christian Heimes529525f2018-05-23 22:24:45 +02003203 server_context.verify_mode = ssl.CERT_REQUIRED
3204 server_context.minimum_version = ssl.TLSVersion.TLSv1_3
3205 client_context.minimum_version = ssl.TLSVersion.TLSv1_3
3206
3207 server = ThreadedEchoServer(
3208 context=server_context, chatty=True, connectionchatty=True,
3209 )
3210 with server, \
3211 client_context.wrap_socket(socket.socket(),
3212 server_hostname=hostname) as s:
3213 # TLS 1.3 perform client cert exchange after handshake
3214 s.connect((HOST, server.port))
3215 try:
3216 s.write(b'data')
3217 s.read(4)
3218 except ssl.SSLError as e:
3219 if support.verbose:
3220 sys.stdout.write("\nSSLError is %r\n" % e)
3221 except OSError as e:
3222 if e.errno != errno.ECONNRESET:
3223 raise
3224 if support.verbose:
3225 sys.stdout.write("\nsocket.error is %r\n" % e)
3226 else:
3227 self.fail("Use of invalid cert should have failed!")
3228
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003229 def test_rude_shutdown(self):
3230 """A brutal shutdown of an SSL server should raise an OSError
3231 in the client when attempting handshake.
3232 """
3233 listener_ready = threading.Event()
3234 listener_gone = threading.Event()
3235
3236 s = socket.socket()
Serhiy Storchaka16994912020-04-25 10:06:29 +03003237 port = socket_helper.bind_port(s, HOST)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003238
3239 # `listener` runs in a thread. It sits in an accept() until
3240 # the main thread connects. Then it rudely closes the socket,
3241 # and sets Event `listener_gone` to let the main thread know
3242 # the socket is gone.
3243 def listener():
3244 s.listen()
3245 listener_ready.set()
3246 newsock, addr = s.accept()
3247 newsock.close()
3248 s.close()
3249 listener_gone.set()
3250
3251 def connector():
3252 listener_ready.wait()
3253 with socket.socket() as c:
3254 c.connect((HOST, port))
3255 listener_gone.wait()
Antoine Pitrou40f08742010-04-24 22:04:40 +00003256 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003257 ssl_sock = test_wrap_socket(c)
3258 except OSError:
3259 pass
3260 else:
3261 self.fail('connecting to closed SSL socket should have failed')
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003262
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003263 t = threading.Thread(target=listener)
3264 t.start()
3265 try:
3266 connector()
3267 finally:
Antoine Pitrou5c89b4e2012-11-11 01:25:36 +01003268 t.join()
Antoine Pitrou5c89b4e2012-11-11 01:25:36 +01003269
Christian Heimesb3ad0e52017-09-08 12:00:19 -07003270 def test_ssl_cert_verify_error(self):
3271 if support.verbose:
3272 sys.stdout.write("\n")
3273
3274 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3275 server_context.load_cert_chain(SIGNED_CERTFILE)
3276
3277 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3278
3279 server = ThreadedEchoServer(context=server_context, chatty=True)
3280 with server:
3281 with context.wrap_socket(socket.socket(),
Christian Heimesa170fa12017-09-15 20:27:30 +02003282 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Christian Heimesb3ad0e52017-09-08 12:00:19 -07003283 try:
3284 s.connect((HOST, server.port))
3285 except ssl.SSLError as e:
3286 msg = 'unable to get local issuer certificate'
3287 self.assertIsInstance(e, ssl.SSLCertVerificationError)
3288 self.assertEqual(e.verify_code, 20)
3289 self.assertEqual(e.verify_message, msg)
3290 self.assertIn(msg, repr(e))
3291 self.assertIn('certificate verify failed', repr(e))
3292
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003293 @requires_tls_version('SSLv2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003294 def test_protocol_sslv2(self):
3295 """Connecting to an SSLv2 server with various client options"""
3296 if support.verbose:
3297 sys.stdout.write("\n")
3298 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
3299 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
3300 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
Christian Heimesa170fa12017-09-15 20:27:30 +02003301 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003302 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003303 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
3304 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
3305 # SSLv23 client with specific SSL options
3306 if no_sslv2_implies_sslv3_hello():
3307 # No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs
Christian Heimesa170fa12017-09-15 20:27:30 +02003308 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003309 client_options=ssl.OP_NO_SSLv2)
Christian Heimesa170fa12017-09-15 20:27:30 +02003310 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003311 client_options=ssl.OP_NO_SSLv3)
Christian Heimesa170fa12017-09-15 20:27:30 +02003312 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003313 client_options=ssl.OP_NO_TLSv1)
Antoine Pitrou242db722013-05-01 20:52:07 +02003314
Christian Heimesa170fa12017-09-15 20:27:30 +02003315 def test_PROTOCOL_TLS(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003316 """Connecting to an SSLv23 server with various client options"""
3317 if support.verbose:
3318 sys.stdout.write("\n")
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003319 if has_tls_version('SSLv2'):
Antoine Pitrou8f85f902012-01-03 22:46:48 +01003320 try:
Christian Heimesa170fa12017-09-15 20:27:30 +02003321 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv2, True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003322 except OSError as x:
3323 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
3324 if support.verbose:
3325 sys.stdout.write(
3326 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
3327 % str(x))
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003328 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003329 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False)
3330 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003331 if has_tls_version('TLSv1'):
3332 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1')
Antoine Pitrou8f85f902012-01-03 22:46:48 +01003333
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003334 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003335 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False, ssl.CERT_OPTIONAL)
3336 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True, ssl.CERT_OPTIONAL)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003337 if has_tls_version('TLSv1'):
3338 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003339
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003340 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003341 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False, ssl.CERT_REQUIRED)
3342 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True, ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003343 if has_tls_version('TLSv1'):
3344 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003345
3346 # Server with specific SSL options
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003347 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003348 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003349 server_options=ssl.OP_NO_SSLv3)
3350 # Will choose TLSv1
Christian Heimesa170fa12017-09-15 20:27:30 +02003351 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003352 server_options=ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003353 if has_tls_version('TLSv1'):
3354 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, False,
3355 server_options=ssl.OP_NO_TLSv1)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003356
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003357 @requires_tls_version('SSLv3')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003358 def test_protocol_sslv3(self):
3359 """Connecting to an SSLv3 server with various client options"""
3360 if support.verbose:
3361 sys.stdout.write("\n")
3362 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3')
3363 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_OPTIONAL)
3364 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003365 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003366 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003367 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003368 client_options=ssl.OP_NO_SSLv3)
3369 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
3370 if no_sslv2_implies_sslv3_hello():
3371 # No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs
Christian Heimesa170fa12017-09-15 20:27:30 +02003372 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLS,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003373 False, client_options=ssl.OP_NO_SSLv2)
3374
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003375 @requires_tls_version('TLSv1')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003376 def test_protocol_tlsv1(self):
3377 """Connecting to a TLSv1 server with various client options"""
3378 if support.verbose:
3379 sys.stdout.write("\n")
3380 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1')
3381 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL)
3382 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003383 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003384 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003385 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003386 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003387 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003388 client_options=ssl.OP_NO_TLSv1)
3389
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003390 @requires_tls_version('TLSv1_1')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003391 def test_protocol_tlsv1_1(self):
3392 """Connecting to a TLSv1.1 server with various client options.
3393 Testing against older TLS versions."""
3394 if support.verbose:
3395 sys.stdout.write("\n")
3396 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1')
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003397 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003398 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003399 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003400 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003401 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003402 client_options=ssl.OP_NO_TLSv1_1)
3403
Christian Heimesa170fa12017-09-15 20:27:30 +02003404 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1')
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003405 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False)
3406 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003407
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003408 @requires_tls_version('TLSv1_2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003409 def test_protocol_tlsv1_2(self):
3410 """Connecting to a TLSv1.2 server with various client options.
3411 Testing against older TLS versions."""
3412 if support.verbose:
3413 sys.stdout.write("\n")
3414 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2',
3415 server_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,
3416 client_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003417 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003418 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003419 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003420 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003421 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003422 client_options=ssl.OP_NO_TLSv1_2)
3423
Christian Heimesa170fa12017-09-15 20:27:30 +02003424 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003425 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1, False)
3426 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_2, False)
3427 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False)
3428 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False)
3429
3430 def test_starttls(self):
3431 """Switching from clear text to encrypted and back again."""
3432 msgs = (b"msg 1", b"MSG 2", b"STARTTLS", b"MSG 3", b"msg 4", b"ENDTLS", b"msg 5", b"msg 6")
3433
3434 server = ThreadedEchoServer(CERTFILE,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003435 starttls_server=True,
3436 chatty=True,
3437 connectionchatty=True)
3438 wrapped = False
3439 with server:
3440 s = socket.socket()
Serhiy Storchaka5eca7f32019-09-01 12:12:52 +03003441 s.setblocking(True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003442 s.connect((HOST, server.port))
Antoine Pitroud6494802011-07-21 01:11:30 +02003443 if support.verbose:
3444 sys.stdout.write("\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003445 for indata in msgs:
Antoine Pitroud6494802011-07-21 01:11:30 +02003446 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003447 sys.stdout.write(
3448 " client: sending %r...\n" % indata)
3449 if wrapped:
3450 conn.write(indata)
3451 outdata = conn.read()
3452 else:
3453 s.send(indata)
3454 outdata = s.recv(1024)
3455 msg = outdata.strip().lower()
3456 if indata == b"STARTTLS" and msg.startswith(b"ok"):
3457 # STARTTLS ok, switch to secure mode
3458 if support.verbose:
3459 sys.stdout.write(
3460 " client: read %r from server, starting TLS...\n"
3461 % msg)
Christian Heimesa170fa12017-09-15 20:27:30 +02003462 conn = test_wrap_socket(s)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003463 wrapped = True
3464 elif indata == b"ENDTLS" and msg.startswith(b"ok"):
3465 # ENDTLS ok, switch back to clear text
3466 if support.verbose:
3467 sys.stdout.write(
3468 " client: read %r from server, ending TLS...\n"
3469 % msg)
3470 s = conn.unwrap()
3471 wrapped = False
3472 else:
3473 if support.verbose:
3474 sys.stdout.write(
3475 " client: read %r from server\n" % msg)
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003476 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003477 sys.stdout.write(" client: closing connection.\n")
3478 if wrapped:
3479 conn.write(b"over\n")
3480 else:
3481 s.send(b"over\n")
3482 if wrapped:
3483 conn.close()
3484 else:
3485 s.close()
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003486
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003487 def test_socketserver(self):
3488 """Using socketserver to create and manage SSL connections."""
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003489 server = make_https_server(self, certfile=SIGNED_CERTFILE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003490 # try to connect
3491 if support.verbose:
3492 sys.stdout.write('\n')
3493 with open(CERTFILE, 'rb') as f:
3494 d1 = f.read()
3495 d2 = ''
3496 # now fetch the same data from the HTTPS server
3497 url = 'https://localhost:%d/%s' % (
3498 server.port, os.path.split(CERTFILE)[1])
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003499 context = ssl.create_default_context(cafile=SIGNING_CA)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003500 f = urllib.request.urlopen(url, context=context)
3501 try:
3502 dlen = f.info().get("content-length")
3503 if dlen and (int(dlen) > 0):
3504 d2 = f.read(int(dlen))
3505 if support.verbose:
3506 sys.stdout.write(
3507 " client: read %d bytes from remote server '%s'\n"
3508 % (len(d2), server))
3509 finally:
3510 f.close()
3511 self.assertEqual(d1, d2)
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003512
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003513 def test_asyncore_server(self):
3514 """Check the example asyncore integration."""
3515 if support.verbose:
3516 sys.stdout.write("\n")
Antoine Pitrou0e576f12011-12-22 10:03:38 +01003517
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003518 indata = b"FOO\n"
3519 server = AsyncoreEchoServer(CERTFILE)
3520 with server:
3521 s = test_wrap_socket(socket.socket())
3522 s.connect(('127.0.0.1', server.port))
3523 if support.verbose:
3524 sys.stdout.write(
3525 " client: sending %r...\n" % indata)
3526 s.write(indata)
3527 outdata = s.read()
3528 if support.verbose:
3529 sys.stdout.write(" client: read %r\n" % outdata)
3530 if outdata != indata.lower():
3531 self.fail(
3532 "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
3533 % (outdata[:20], len(outdata),
3534 indata[:20].lower(), len(indata)))
3535 s.write(b"over\n")
3536 if support.verbose:
3537 sys.stdout.write(" client: closing connection.\n")
3538 s.close()
3539 if support.verbose:
3540 sys.stdout.write(" client: connection closed.\n")
Benjamin Petersoncca27322015-01-23 16:35:37 -05003541
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003542 def test_recv_send(self):
3543 """Test recv(), send() and friends."""
3544 if support.verbose:
3545 sys.stdout.write("\n")
3546
3547 server = ThreadedEchoServer(CERTFILE,
3548 certreqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003549 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003550 cacerts=CERTFILE,
3551 chatty=True,
3552 connectionchatty=False)
3553 with server:
3554 s = test_wrap_socket(socket.socket(),
3555 server_side=False,
3556 certfile=CERTFILE,
3557 ca_certs=CERTFILE,
3558 cert_reqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003559 ssl_version=ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003560 s.connect((HOST, server.port))
3561 # helper methods for standardising recv* method signatures
3562 def _recv_into():
3563 b = bytearray(b"\0"*100)
3564 count = s.recv_into(b)
3565 return b[:count]
3566
3567 def _recvfrom_into():
3568 b = bytearray(b"\0"*100)
3569 count, addr = s.recvfrom_into(b)
3570 return b[:count]
3571
3572 # (name, method, expect success?, *args, return value func)
3573 send_methods = [
3574 ('send', s.send, True, [], len),
3575 ('sendto', s.sendto, False, ["some.address"], len),
3576 ('sendall', s.sendall, True, [], lambda x: None),
3577 ]
3578 # (name, method, whether to expect success, *args)
3579 recv_methods = [
3580 ('recv', s.recv, True, []),
3581 ('recvfrom', s.recvfrom, False, ["some.address"]),
3582 ('recv_into', _recv_into, True, []),
3583 ('recvfrom_into', _recvfrom_into, False, []),
3584 ]
3585 data_prefix = "PREFIX_"
3586
3587 for (meth_name, send_meth, expect_success, args,
3588 ret_val_meth) in send_methods:
3589 indata = (data_prefix + meth_name).encode('ascii')
3590 try:
3591 ret = send_meth(indata, *args)
3592 msg = "sending with {}".format(meth_name)
3593 self.assertEqual(ret, ret_val_meth(indata), msg=msg)
3594 outdata = s.read()
3595 if outdata != indata.lower():
3596 self.fail(
3597 "While sending with <<{name:s}>> bad data "
3598 "<<{outdata:r}>> ({nout:d}) received; "
3599 "expected <<{indata:r}>> ({nin:d})\n".format(
3600 name=meth_name, outdata=outdata[:20],
3601 nout=len(outdata),
3602 indata=indata[:20], nin=len(indata)
3603 )
3604 )
3605 except ValueError as e:
3606 if expect_success:
3607 self.fail(
3608 "Failed to send with method <<{name:s}>>; "
3609 "expected to succeed.\n".format(name=meth_name)
3610 )
3611 if not str(e).startswith(meth_name):
3612 self.fail(
3613 "Method <<{name:s}>> failed with unexpected "
3614 "exception message: {exp:s}\n".format(
3615 name=meth_name, exp=e
3616 )
3617 )
3618
3619 for meth_name, recv_meth, expect_success, args in recv_methods:
3620 indata = (data_prefix + meth_name).encode('ascii')
3621 try:
3622 s.send(indata)
3623 outdata = recv_meth(*args)
3624 if outdata != indata.lower():
3625 self.fail(
3626 "While receiving with <<{name:s}>> bad data "
3627 "<<{outdata:r}>> ({nout:d}) received; "
3628 "expected <<{indata:r}>> ({nin:d})\n".format(
3629 name=meth_name, outdata=outdata[:20],
3630 nout=len(outdata),
3631 indata=indata[:20], nin=len(indata)
3632 )
3633 )
3634 except ValueError as e:
3635 if expect_success:
3636 self.fail(
3637 "Failed to receive with method <<{name:s}>>; "
3638 "expected to succeed.\n".format(name=meth_name)
3639 )
3640 if not str(e).startswith(meth_name):
3641 self.fail(
3642 "Method <<{name:s}>> failed with unexpected "
3643 "exception message: {exp:s}\n".format(
3644 name=meth_name, exp=e
3645 )
3646 )
3647 # consume data
3648 s.read()
3649
3650 # read(-1, buffer) is supported, even though read(-1) is not
3651 data = b"data"
3652 s.send(data)
3653 buffer = bytearray(len(data))
3654 self.assertEqual(s.read(-1, buffer), len(data))
3655 self.assertEqual(buffer, data)
3656
Christian Heimes888bbdc2017-09-07 14:18:21 -07003657 # sendall accepts bytes-like objects
3658 if ctypes is not None:
3659 ubyte = ctypes.c_ubyte * len(data)
3660 byteslike = ubyte.from_buffer_copy(data)
3661 s.sendall(byteslike)
3662 self.assertEqual(s.read(), data)
3663
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003664 # Make sure sendmsg et al are disallowed to avoid
3665 # inadvertent disclosure of data and/or corruption
3666 # of the encrypted data stream
Serhiy Storchaka42b1d612018-12-06 22:36:55 +02003667 self.assertRaises(NotImplementedError, s.dup)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003668 self.assertRaises(NotImplementedError, s.sendmsg, [b"data"])
3669 self.assertRaises(NotImplementedError, s.recvmsg, 100)
3670 self.assertRaises(NotImplementedError,
Serhiy Storchaka42b1d612018-12-06 22:36:55 +02003671 s.recvmsg_into, [bytearray(100)])
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003672 s.write(b"over\n")
3673
3674 self.assertRaises(ValueError, s.recv, -1)
3675 self.assertRaises(ValueError, s.read, -1)
3676
3677 s.close()
3678
3679 def test_recv_zero(self):
3680 server = ThreadedEchoServer(CERTFILE)
3681 server.__enter__()
3682 self.addCleanup(server.__exit__, None, None)
3683 s = socket.create_connection((HOST, server.port))
3684 self.addCleanup(s.close)
3685 s = test_wrap_socket(s, suppress_ragged_eofs=False)
3686 self.addCleanup(s.close)
3687
3688 # recv/read(0) should return no data
3689 s.send(b"data")
3690 self.assertEqual(s.recv(0), b"")
3691 self.assertEqual(s.read(0), b"")
3692 self.assertEqual(s.read(), b"data")
3693
3694 # Should not block if the other end sends no data
3695 s.setblocking(False)
3696 self.assertEqual(s.recv(0), b"")
3697 self.assertEqual(s.recv_into(bytearray()), 0)
3698
3699 def test_nonblocking_send(self):
3700 server = ThreadedEchoServer(CERTFILE,
3701 certreqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003702 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003703 cacerts=CERTFILE,
3704 chatty=True,
3705 connectionchatty=False)
3706 with server:
3707 s = test_wrap_socket(socket.socket(),
3708 server_side=False,
3709 certfile=CERTFILE,
3710 ca_certs=CERTFILE,
3711 cert_reqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003712 ssl_version=ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003713 s.connect((HOST, server.port))
3714 s.setblocking(False)
3715
3716 # If we keep sending data, at some point the buffers
3717 # will be full and the call will block
3718 buf = bytearray(8192)
3719 def fill_buffer():
3720 while True:
3721 s.send(buf)
3722 self.assertRaises((ssl.SSLWantWriteError,
3723 ssl.SSLWantReadError), fill_buffer)
3724
3725 # Now read all the output and discard it
3726 s.setblocking(True)
3727 s.close()
3728
3729 def test_handshake_timeout(self):
3730 # Issue #5103: SSL handshake must respect the socket timeout
3731 server = socket.socket(socket.AF_INET)
3732 host = "127.0.0.1"
Serhiy Storchaka16994912020-04-25 10:06:29 +03003733 port = socket_helper.bind_port(server)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003734 started = threading.Event()
3735 finish = False
3736
3737 def serve():
3738 server.listen()
3739 started.set()
3740 conns = []
3741 while not finish:
3742 r, w, e = select.select([server], [], [], 0.1)
3743 if server in r:
3744 # Let the socket hang around rather than having
3745 # it closed by garbage collection.
3746 conns.append(server.accept()[0])
3747 for sock in conns:
3748 sock.close()
3749
3750 t = threading.Thread(target=serve)
3751 t.start()
3752 started.wait()
3753
3754 try:
3755 try:
3756 c = socket.socket(socket.AF_INET)
3757 c.settimeout(0.2)
3758 c.connect((host, port))
3759 # Will attempt handshake and time out
Christian Heimes03c8ddd2020-11-20 09:26:07 +01003760 self.assertRaisesRegex(TimeoutError, "timed out",
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003761 test_wrap_socket, c)
3762 finally:
3763 c.close()
3764 try:
3765 c = socket.socket(socket.AF_INET)
3766 c = test_wrap_socket(c)
3767 c.settimeout(0.2)
3768 # Will attempt handshake and time out
Christian Heimes03c8ddd2020-11-20 09:26:07 +01003769 self.assertRaisesRegex(TimeoutError, "timed out",
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003770 c.connect, (host, port))
3771 finally:
3772 c.close()
3773 finally:
3774 finish = True
3775 t.join()
3776 server.close()
3777
3778 def test_server_accept(self):
3779 # Issue #16357: accept() on a SSLSocket created through
3780 # SSLContext.wrap_socket().
Christian Heimesa170fa12017-09-15 20:27:30 +02003781 context = ssl.SSLContext(ssl.PROTOCOL_TLS)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003782 context.verify_mode = ssl.CERT_REQUIRED
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003783 context.load_verify_locations(SIGNING_CA)
3784 context.load_cert_chain(SIGNED_CERTFILE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003785 server = socket.socket(socket.AF_INET)
3786 host = "127.0.0.1"
Serhiy Storchaka16994912020-04-25 10:06:29 +03003787 port = socket_helper.bind_port(server)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003788 server = context.wrap_socket(server, server_side=True)
3789 self.assertTrue(server.server_side)
3790
3791 evt = threading.Event()
3792 remote = None
3793 peer = None
3794 def serve():
3795 nonlocal remote, peer
3796 server.listen()
3797 # Block on the accept and wait on the connection to close.
3798 evt.set()
3799 remote, peer = server.accept()
Christian Heimes529525f2018-05-23 22:24:45 +02003800 remote.send(remote.recv(4))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003801
3802 t = threading.Thread(target=serve)
3803 t.start()
3804 # Client wait until server setup and perform a connect.
3805 evt.wait()
3806 client = context.wrap_socket(socket.socket())
3807 client.connect((host, port))
Christian Heimes529525f2018-05-23 22:24:45 +02003808 client.send(b'data')
3809 client.recv()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003810 client_addr = client.getsockname()
3811 client.close()
3812 t.join()
3813 remote.close()
3814 server.close()
3815 # Sanity checks.
3816 self.assertIsInstance(remote, ssl.SSLSocket)
3817 self.assertEqual(peer, client_addr)
3818
3819 def test_getpeercert_enotconn(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02003820 context = ssl.SSLContext(ssl.PROTOCOL_TLS)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003821 with context.wrap_socket(socket.socket()) as sock:
3822 with self.assertRaises(OSError) as cm:
3823 sock.getpeercert()
3824 self.assertEqual(cm.exception.errno, errno.ENOTCONN)
3825
3826 def test_do_handshake_enotconn(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02003827 context = ssl.SSLContext(ssl.PROTOCOL_TLS)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003828 with context.wrap_socket(socket.socket()) as sock:
3829 with self.assertRaises(OSError) as cm:
3830 sock.do_handshake()
3831 self.assertEqual(cm.exception.errno, errno.ENOTCONN)
3832
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003833 def test_no_shared_ciphers(self):
3834 client_context, server_context, hostname = testing_context()
3835 # OpenSSL enables all TLS 1.3 ciphers, enforce TLS 1.2 for test
3836 client_context.options |= ssl.OP_NO_TLSv1_3
Victor Stinner5e922652018-09-07 17:30:33 +02003837 # Force different suites on client and server
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003838 client_context.set_ciphers("AES128")
3839 server_context.set_ciphers("AES256")
3840 with ThreadedEchoServer(context=server_context) as server:
3841 with client_context.wrap_socket(socket.socket(),
3842 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003843 with self.assertRaises(OSError):
3844 s.connect((HOST, server.port))
3845 self.assertIn("no shared cipher", server.conn_errors[0])
3846
3847 def test_version_basic(self):
3848 """
3849 Basic tests for SSLSocket.version().
3850 More tests are done in the test_protocol_*() methods.
3851 """
Christian Heimesa170fa12017-09-15 20:27:30 +02003852 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3853 context.check_hostname = False
3854 context.verify_mode = ssl.CERT_NONE
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003855 with ThreadedEchoServer(CERTFILE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003856 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003857 chatty=False) as server:
3858 with context.wrap_socket(socket.socket()) as s:
3859 self.assertIs(s.version(), None)
Christian Heimes141c5e82018-02-24 21:10:57 +01003860 self.assertIs(s._sslobj, None)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003861 s.connect((HOST, server.port))
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003862 if IS_OPENSSL_1_1_1 and has_tls_version('TLSv1_3'):
Christian Heimes05d9fe32018-02-27 08:55:39 +01003863 self.assertEqual(s.version(), 'TLSv1.3')
3864 elif ssl.OPENSSL_VERSION_INFO >= (1, 0, 2):
Christian Heimesa170fa12017-09-15 20:27:30 +02003865 self.assertEqual(s.version(), 'TLSv1.2')
3866 else: # 0.9.8 to 1.0.1
3867 self.assertIn(s.version(), ('TLSv1', 'TLSv1.2'))
Christian Heimes141c5e82018-02-24 21:10:57 +01003868 self.assertIs(s._sslobj, None)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003869 self.assertIs(s.version(), None)
3870
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003871 @requires_tls_version('TLSv1_3')
Christian Heimescb5b68a2017-09-07 18:07:00 -07003872 def test_tls1_3(self):
3873 context = ssl.SSLContext(ssl.PROTOCOL_TLS)
3874 context.load_cert_chain(CERTFILE)
Christian Heimescb5b68a2017-09-07 18:07:00 -07003875 context.options |= (
3876 ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_TLSv1_2
3877 )
3878 with ThreadedEchoServer(context=context) as server:
3879 with context.wrap_socket(socket.socket()) as s:
3880 s.connect((HOST, server.port))
Christian Heimes05d9fe32018-02-27 08:55:39 +01003881 self.assertIn(s.cipher()[0], {
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003882 'TLS_AES_256_GCM_SHA384',
3883 'TLS_CHACHA20_POLY1305_SHA256',
3884 'TLS_AES_128_GCM_SHA256',
Christian Heimes05d9fe32018-02-27 08:55:39 +01003885 })
3886 self.assertEqual(s.version(), 'TLSv1.3')
Christian Heimescb5b68a2017-09-07 18:07:00 -07003887
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003888 @requires_minimum_version
3889 @requires_tls_version('TLSv1_2')
3890 def test_min_max_version_tlsv1_2(self):
Christian Heimes698dde12018-02-27 11:54:43 +01003891 client_context, server_context, hostname = testing_context()
3892 # client TLSv1.0 to 1.2
3893 client_context.minimum_version = ssl.TLSVersion.TLSv1
3894 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
3895 # server only TLSv1.2
3896 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
3897 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
3898
3899 with ThreadedEchoServer(context=server_context) as server:
3900 with client_context.wrap_socket(socket.socket(),
3901 server_hostname=hostname) as s:
3902 s.connect((HOST, server.port))
3903 self.assertEqual(s.version(), 'TLSv1.2')
3904
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003905 @requires_minimum_version
3906 @requires_tls_version('TLSv1_1')
3907 def test_min_max_version_tlsv1_1(self):
3908 client_context, server_context, hostname = testing_context()
Christian Heimes698dde12018-02-27 11:54:43 +01003909 # client 1.0 to 1.2, server 1.0 to 1.1
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003910 client_context.minimum_version = ssl.TLSVersion.TLSv1
3911 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimes698dde12018-02-27 11:54:43 +01003912 server_context.minimum_version = ssl.TLSVersion.TLSv1
3913 server_context.maximum_version = ssl.TLSVersion.TLSv1_1
Christian Heimesf6c6b582021-03-18 23:06:50 +01003914 seclevel_workaround(client_context, server_context)
Christian Heimes698dde12018-02-27 11:54:43 +01003915
3916 with ThreadedEchoServer(context=server_context) as server:
3917 with client_context.wrap_socket(socket.socket(),
3918 server_hostname=hostname) as s:
3919 s.connect((HOST, server.port))
3920 self.assertEqual(s.version(), 'TLSv1.1')
3921
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003922 @requires_minimum_version
3923 @requires_tls_version('TLSv1_2')
Christian Heimesce04e712020-11-18 13:10:53 +01003924 @requires_tls_version('TLSv1')
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003925 def test_min_max_version_mismatch(self):
3926 client_context, server_context, hostname = testing_context()
Christian Heimes698dde12018-02-27 11:54:43 +01003927 # client 1.0, server 1.2 (mismatch)
Christian Heimes698dde12018-02-27 11:54:43 +01003928 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesc9bc49c2019-09-11 19:24:47 +02003929 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
Christian Heimese35d1ba2019-06-03 20:40:15 +02003930 client_context.maximum_version = ssl.TLSVersion.TLSv1
Christian Heimesde606ea2019-09-11 19:48:58 +02003931 client_context.minimum_version = ssl.TLSVersion.TLSv1
Christian Heimesf6c6b582021-03-18 23:06:50 +01003932 seclevel_workaround(client_context, server_context)
3933
Christian Heimes698dde12018-02-27 11:54:43 +01003934 with ThreadedEchoServer(context=server_context) as server:
3935 with client_context.wrap_socket(socket.socket(),
3936 server_hostname=hostname) as s:
3937 with self.assertRaises(ssl.SSLError) as e:
3938 s.connect((HOST, server.port))
3939 self.assertIn("alert", str(e.exception))
3940
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003941 @requires_minimum_version
3942 @requires_tls_version('SSLv3')
Christian Heimes698dde12018-02-27 11:54:43 +01003943 def test_min_max_version_sslv3(self):
3944 client_context, server_context, hostname = testing_context()
3945 server_context.minimum_version = ssl.TLSVersion.SSLv3
3946 client_context.minimum_version = ssl.TLSVersion.SSLv3
3947 client_context.maximum_version = ssl.TLSVersion.SSLv3
Christian Heimesf6c6b582021-03-18 23:06:50 +01003948 seclevel_workaround(client_context, server_context)
3949
Christian Heimes698dde12018-02-27 11:54:43 +01003950 with ThreadedEchoServer(context=server_context) as server:
3951 with client_context.wrap_socket(socket.socket(),
3952 server_hostname=hostname) as s:
3953 s.connect((HOST, server.port))
3954 self.assertEqual(s.version(), 'SSLv3')
3955
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003956 @unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL")
3957 def test_default_ecdh_curve(self):
3958 # Issue #21015: elliptic curve-based Diffie Hellman key exchange
3959 # should be enabled by default on SSL contexts.
Christian Heimesa170fa12017-09-15 20:27:30 +02003960 context = ssl.SSLContext(ssl.PROTOCOL_TLS)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003961 context.load_cert_chain(CERTFILE)
Christian Heimescb5b68a2017-09-07 18:07:00 -07003962 # TLSv1.3 defaults to PFS key agreement and no longer has KEA in
3963 # cipher name.
3964 context.options |= ssl.OP_NO_TLSv1_3
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003965 # Prior to OpenSSL 1.0.0, ECDH ciphers have to be enabled
3966 # explicitly using the 'ECCdraft' cipher alias. Otherwise,
3967 # our default cipher list should prefer ECDH-based ciphers
3968 # automatically.
3969 if ssl.OPENSSL_VERSION_INFO < (1, 0, 0):
3970 context.set_ciphers("ECCdraft:ECDH")
3971 with ThreadedEchoServer(context=context) as server:
3972 with context.wrap_socket(socket.socket()) as s:
3973 s.connect((HOST, server.port))
3974 self.assertIn("ECDH", s.cipher()[0])
3975
3976 @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES,
3977 "'tls-unique' channel binding not available")
3978 def test_tls_unique_channel_binding(self):
3979 """Test tls-unique channel binding."""
3980 if support.verbose:
3981 sys.stdout.write("\n")
3982
Christian Heimes05d9fe32018-02-27 08:55:39 +01003983 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01003984
3985 server = ThreadedEchoServer(context=server_context,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003986 chatty=True,
3987 connectionchatty=False)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003988
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003989 with server:
Christian Heimes05d9fe32018-02-27 08:55:39 +01003990 with client_context.wrap_socket(
3991 socket.socket(),
3992 server_hostname=hostname) as s:
3993 s.connect((HOST, server.port))
3994 # get the data
3995 cb_data = s.get_channel_binding("tls-unique")
3996 if support.verbose:
3997 sys.stdout.write(
3998 " got channel binding data: {0!r}\n".format(cb_data))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003999
Christian Heimes05d9fe32018-02-27 08:55:39 +01004000 # check if it is sane
4001 self.assertIsNotNone(cb_data)
Christian Heimes529525f2018-05-23 22:24:45 +02004002 if s.version() == 'TLSv1.3':
4003 self.assertEqual(len(cb_data), 48)
4004 else:
4005 self.assertEqual(len(cb_data), 12) # True for TLSv1
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004006
Christian Heimes05d9fe32018-02-27 08:55:39 +01004007 # and compare with the peers version
4008 s.write(b"CB tls-unique\n")
4009 peer_data_repr = s.read().strip()
4010 self.assertEqual(peer_data_repr,
4011 repr(cb_data).encode("us-ascii"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004012
4013 # now, again
Christian Heimes05d9fe32018-02-27 08:55:39 +01004014 with client_context.wrap_socket(
4015 socket.socket(),
4016 server_hostname=hostname) as s:
4017 s.connect((HOST, server.port))
4018 new_cb_data = s.get_channel_binding("tls-unique")
4019 if support.verbose:
4020 sys.stdout.write(
4021 "got another channel binding data: {0!r}\n".format(
4022 new_cb_data)
4023 )
4024 # is it really unique
4025 self.assertNotEqual(cb_data, new_cb_data)
4026 self.assertIsNotNone(cb_data)
Christian Heimes529525f2018-05-23 22:24:45 +02004027 if s.version() == 'TLSv1.3':
4028 self.assertEqual(len(cb_data), 48)
4029 else:
4030 self.assertEqual(len(cb_data), 12) # True for TLSv1
Christian Heimes05d9fe32018-02-27 08:55:39 +01004031 s.write(b"CB tls-unique\n")
4032 peer_data_repr = s.read().strip()
4033 self.assertEqual(peer_data_repr,
4034 repr(new_cb_data).encode("us-ascii"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004035
4036 def test_compression(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004037 client_context, server_context, hostname = testing_context()
4038 stats = server_params_test(client_context, server_context,
4039 chatty=True, connectionchatty=True,
4040 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004041 if support.verbose:
4042 sys.stdout.write(" got compression: {!r}\n".format(stats['compression']))
4043 self.assertIn(stats['compression'], { None, 'ZLIB', 'RLE' })
4044
4045 @unittest.skipUnless(hasattr(ssl, 'OP_NO_COMPRESSION'),
4046 "ssl.OP_NO_COMPRESSION needed for this test")
4047 def test_compression_disabled(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004048 client_context, server_context, hostname = testing_context()
4049 client_context.options |= ssl.OP_NO_COMPRESSION
4050 server_context.options |= ssl.OP_NO_COMPRESSION
4051 stats = server_params_test(client_context, server_context,
4052 chatty=True, connectionchatty=True,
4053 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004054 self.assertIs(stats['compression'], None)
4055
Paul Monsonf3550692019-06-19 13:09:54 -07004056 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004057 def test_dh_params(self):
4058 # Check we can get a connection with ephemeral Diffie-Hellman
Christian Heimesa170fa12017-09-15 20:27:30 +02004059 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004060 # test scenario needs TLS <= 1.2
4061 client_context.options |= ssl.OP_NO_TLSv1_3
Christian Heimesa170fa12017-09-15 20:27:30 +02004062 server_context.load_dh_params(DHFILE)
4063 server_context.set_ciphers("kEDH")
Christian Heimes05d9fe32018-02-27 08:55:39 +01004064 server_context.options |= ssl.OP_NO_TLSv1_3
Christian Heimesa170fa12017-09-15 20:27:30 +02004065 stats = server_params_test(client_context, server_context,
4066 chatty=True, connectionchatty=True,
4067 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004068 cipher = stats["cipher"][0]
4069 parts = cipher.split("-")
4070 if "ADH" not in parts and "EDH" not in parts and "DHE" not in parts:
4071 self.fail("Non-DH cipher: " + cipher[0])
4072
Christian Heimesb7b92252018-02-25 09:49:31 +01004073 @unittest.skipUnless(HAVE_SECP_CURVES, "needs secp384r1 curve support")
Christian Heimes05d9fe32018-02-27 08:55:39 +01004074 @unittest.skipIf(IS_OPENSSL_1_1_1, "TODO: Test doesn't work on 1.1.1")
Christian Heimesb7b92252018-02-25 09:49:31 +01004075 def test_ecdh_curve(self):
4076 # server secp384r1, client auto
4077 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004078
Christian Heimesb7b92252018-02-25 09:49:31 +01004079 server_context.set_ecdh_curve("secp384r1")
4080 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
4081 server_context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
4082 stats = server_params_test(client_context, server_context,
4083 chatty=True, connectionchatty=True,
4084 sni_name=hostname)
4085
4086 # server auto, client secp384r1
4087 client_context, server_context, hostname = testing_context()
4088 client_context.set_ecdh_curve("secp384r1")
4089 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
4090 server_context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
4091 stats = server_params_test(client_context, server_context,
4092 chatty=True, connectionchatty=True,
4093 sni_name=hostname)
4094
4095 # server / client curve mismatch
4096 client_context, server_context, hostname = testing_context()
4097 client_context.set_ecdh_curve("prime256v1")
4098 server_context.set_ecdh_curve("secp384r1")
4099 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
4100 server_context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
4101 try:
4102 stats = server_params_test(client_context, server_context,
4103 chatty=True, connectionchatty=True,
4104 sni_name=hostname)
4105 except ssl.SSLError:
4106 pass
4107 else:
4108 # OpenSSL 1.0.2 does not fail although it should.
Christian Heimes05d9fe32018-02-27 08:55:39 +01004109 if IS_OPENSSL_1_1_0:
Christian Heimesb7b92252018-02-25 09:49:31 +01004110 self.fail("mismatch curve did not fail")
4111
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004112 def test_selected_alpn_protocol(self):
4113 # selected_alpn_protocol() is None unless ALPN is used.
Christian Heimesa170fa12017-09-15 20:27:30 +02004114 client_context, server_context, hostname = testing_context()
4115 stats = server_params_test(client_context, server_context,
4116 chatty=True, connectionchatty=True,
4117 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004118 self.assertIs(stats['client_alpn_protocol'], None)
4119
4120 @unittest.skipUnless(ssl.HAS_ALPN, "ALPN support required")
4121 def test_selected_alpn_protocol_if_server_uses_alpn(self):
4122 # selected_alpn_protocol() is None unless ALPN is used by the client.
Christian Heimesa170fa12017-09-15 20:27:30 +02004123 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004124 server_context.set_alpn_protocols(['foo', 'bar'])
4125 stats = server_params_test(client_context, server_context,
Christian Heimesa170fa12017-09-15 20:27:30 +02004126 chatty=True, connectionchatty=True,
4127 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004128 self.assertIs(stats['client_alpn_protocol'], None)
4129
4130 @unittest.skipUnless(ssl.HAS_ALPN, "ALPN support needed for this test")
4131 def test_alpn_protocols(self):
4132 server_protocols = ['foo', 'bar', 'milkshake']
4133 protocol_tests = [
4134 (['foo', 'bar'], 'foo'),
4135 (['bar', 'foo'], 'foo'),
4136 (['milkshake'], 'milkshake'),
4137 (['http/3.0', 'http/4.0'], None)
4138 ]
4139 for client_protocols, expected in protocol_tests:
Christian Heimesa170fa12017-09-15 20:27:30 +02004140 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004141 server_context.set_alpn_protocols(server_protocols)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004142 client_context.set_alpn_protocols(client_protocols)
4143
4144 try:
4145 stats = server_params_test(client_context,
4146 server_context,
4147 chatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02004148 connectionchatty=True,
4149 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004150 except ssl.SSLError as e:
4151 stats = e
4152
Christian Heimes05d9fe32018-02-27 08:55:39 +01004153 if (expected is None and IS_OPENSSL_1_1_0
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004154 and ssl.OPENSSL_VERSION_INFO < (1, 1, 0, 6)):
4155 # OpenSSL 1.1.0 to 1.1.0e raises handshake error
4156 self.assertIsInstance(stats, ssl.SSLError)
4157 else:
4158 msg = "failed trying %s (s) and %s (c).\n" \
4159 "was expecting %s, but got %%s from the %%s" \
4160 % (str(server_protocols), str(client_protocols),
4161 str(expected))
4162 client_result = stats['client_alpn_protocol']
4163 self.assertEqual(client_result, expected,
4164 msg % (client_result, "client"))
4165 server_result = stats['server_alpn_protocols'][-1] \
4166 if len(stats['server_alpn_protocols']) else 'nothing'
4167 self.assertEqual(server_result, expected,
4168 msg % (server_result, "server"))
4169
4170 def test_selected_npn_protocol(self):
4171 # selected_npn_protocol() is None unless NPN is used
Christian Heimesa170fa12017-09-15 20:27:30 +02004172 client_context, server_context, hostname = testing_context()
4173 stats = server_params_test(client_context, server_context,
4174 chatty=True, connectionchatty=True,
4175 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004176 self.assertIs(stats['client_npn_protocol'], None)
4177
4178 @unittest.skipUnless(ssl.HAS_NPN, "NPN support needed for this test")
4179 def test_npn_protocols(self):
4180 server_protocols = ['http/1.1', 'spdy/2']
4181 protocol_tests = [
4182 (['http/1.1', 'spdy/2'], 'http/1.1'),
4183 (['spdy/2', 'http/1.1'], 'http/1.1'),
4184 (['spdy/2', 'test'], 'spdy/2'),
4185 (['abc', 'def'], 'abc')
4186 ]
4187 for client_protocols, expected in protocol_tests:
Christian Heimesa170fa12017-09-15 20:27:30 +02004188 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004189 server_context.set_npn_protocols(server_protocols)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004190 client_context.set_npn_protocols(client_protocols)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004191 stats = server_params_test(client_context, server_context,
Christian Heimesa170fa12017-09-15 20:27:30 +02004192 chatty=True, connectionchatty=True,
4193 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004194 msg = "failed trying %s (s) and %s (c).\n" \
4195 "was expecting %s, but got %%s from the %%s" \
4196 % (str(server_protocols), str(client_protocols),
4197 str(expected))
4198 client_result = stats['client_npn_protocol']
4199 self.assertEqual(client_result, expected, msg % (client_result, "client"))
4200 server_result = stats['server_npn_protocols'][-1] \
4201 if len(stats['server_npn_protocols']) else 'nothing'
4202 self.assertEqual(server_result, expected, msg % (server_result, "server"))
4203
4204 def sni_contexts(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004205 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004206 server_context.load_cert_chain(SIGNED_CERTFILE)
Christian Heimesa170fa12017-09-15 20:27:30 +02004207 other_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004208 other_context.load_cert_chain(SIGNED_CERTFILE2)
Christian Heimesa170fa12017-09-15 20:27:30 +02004209 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004210 client_context.load_verify_locations(SIGNING_CA)
4211 return server_context, other_context, client_context
4212
4213 def check_common_name(self, stats, name):
4214 cert = stats['peercert']
4215 self.assertIn((('commonName', name),), cert['subject'])
4216
4217 @needs_sni
4218 def test_sni_callback(self):
4219 calls = []
4220 server_context, other_context, client_context = self.sni_contexts()
4221
Christian Heimesa170fa12017-09-15 20:27:30 +02004222 client_context.check_hostname = False
4223
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004224 def servername_cb(ssl_sock, server_name, initial_context):
4225 calls.append((server_name, initial_context))
4226 if server_name is not None:
4227 ssl_sock.context = other_context
4228 server_context.set_servername_callback(servername_cb)
4229
4230 stats = server_params_test(client_context, server_context,
4231 chatty=True,
4232 sni_name='supermessage')
4233 # The hostname was fetched properly, and the certificate was
4234 # changed for the connection.
4235 self.assertEqual(calls, [("supermessage", server_context)])
4236 # CERTFILE4 was selected
4237 self.check_common_name(stats, 'fakehostname')
4238
4239 calls = []
4240 # The callback is called with server_name=None
4241 stats = server_params_test(client_context, server_context,
4242 chatty=True,
4243 sni_name=None)
4244 self.assertEqual(calls, [(None, server_context)])
Christian Heimesa170fa12017-09-15 20:27:30 +02004245 self.check_common_name(stats, SIGNED_CERTFILE_HOSTNAME)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004246
4247 # Check disabling the callback
4248 calls = []
4249 server_context.set_servername_callback(None)
4250
4251 stats = server_params_test(client_context, server_context,
4252 chatty=True,
4253 sni_name='notfunny')
4254 # Certificate didn't change
Christian Heimesa170fa12017-09-15 20:27:30 +02004255 self.check_common_name(stats, SIGNED_CERTFILE_HOSTNAME)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004256 self.assertEqual(calls, [])
4257
4258 @needs_sni
4259 def test_sni_callback_alert(self):
4260 # Returning a TLS alert is reflected to the connecting client
4261 server_context, other_context, client_context = self.sni_contexts()
4262
4263 def cb_returning_alert(ssl_sock, server_name, initial_context):
4264 return ssl.ALERT_DESCRIPTION_ACCESS_DENIED
4265 server_context.set_servername_callback(cb_returning_alert)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004266 with self.assertRaises(ssl.SSLError) as cm:
4267 stats = server_params_test(client_context, server_context,
4268 chatty=False,
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004269 sni_name='supermessage')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004270 self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_ACCESS_DENIED')
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004271
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004272 @needs_sni
4273 def test_sni_callback_raising(self):
4274 # Raising fails the connection with a TLS handshake failure alert.
4275 server_context, other_context, client_context = self.sni_contexts()
4276
4277 def cb_raising(ssl_sock, server_name, initial_context):
4278 1/0
4279 server_context.set_servername_callback(cb_raising)
4280
Victor Stinner00253502019-06-03 03:51:43 +02004281 with support.catch_unraisable_exception() as catch:
4282 with self.assertRaises(ssl.SSLError) as cm:
4283 stats = server_params_test(client_context, server_context,
4284 chatty=False,
4285 sni_name='supermessage')
4286
4287 self.assertEqual(cm.exception.reason,
4288 'SSLV3_ALERT_HANDSHAKE_FAILURE')
4289 self.assertEqual(catch.unraisable.exc_type, ZeroDivisionError)
Antoine Pitrou50b24d02013-04-11 20:48:42 +02004290
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004291 @needs_sni
4292 def test_sni_callback_wrong_return_type(self):
4293 # Returning the wrong return type terminates the TLS connection
4294 # with an internal error alert.
4295 server_context, other_context, client_context = self.sni_contexts()
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004296
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004297 def cb_wrong_return_type(ssl_sock, server_name, initial_context):
4298 return "foo"
4299 server_context.set_servername_callback(cb_wrong_return_type)
4300
Victor Stinner00253502019-06-03 03:51:43 +02004301 with support.catch_unraisable_exception() as catch:
4302 with self.assertRaises(ssl.SSLError) as cm:
4303 stats = server_params_test(client_context, server_context,
4304 chatty=False,
4305 sni_name='supermessage')
4306
4307
4308 self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_INTERNAL_ERROR')
4309 self.assertEqual(catch.unraisable.exc_type, TypeError)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004310
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004311 def test_shared_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004312 client_context, server_context, hostname = testing_context()
Christian Heimese8eb6cb2018-05-22 22:50:12 +02004313 client_context.set_ciphers("AES128:AES256")
4314 server_context.set_ciphers("AES256")
4315 expected_algs = [
4316 "AES256", "AES-256",
4317 # TLS 1.3 ciphers are always enabled
4318 "TLS_CHACHA20", "TLS_AES",
4319 ]
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004320
Christian Heimesa170fa12017-09-15 20:27:30 +02004321 stats = server_params_test(client_context, server_context,
4322 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004323 ciphers = stats['server_shared_ciphers'][0]
4324 self.assertGreater(len(ciphers), 0)
4325 for name, tls_version, bits in ciphers:
Christian Heimese8eb6cb2018-05-22 22:50:12 +02004326 if not any(alg in name for alg in expected_algs):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004327 self.fail(name)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004328
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004329 def test_read_write_after_close_raises_valuerror(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004330 client_context, server_context, hostname = testing_context()
4331 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004332
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004333 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02004334 s = client_context.wrap_socket(socket.socket(),
4335 server_hostname=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004336 s.connect((HOST, server.port))
4337 s.close()
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004338
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004339 self.assertRaises(ValueError, s.read, 1024)
4340 self.assertRaises(ValueError, s.write, b'hello')
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004341
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004342 def test_sendfile(self):
4343 TEST_DATA = b"x" * 512
Hai Shia7f5d932020-08-04 00:41:24 +08004344 with open(os_helper.TESTFN, 'wb') as f:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004345 f.write(TEST_DATA)
Hai Shia7f5d932020-08-04 00:41:24 +08004346 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesa170fa12017-09-15 20:27:30 +02004347 context = ssl.SSLContext(ssl.PROTOCOL_TLS)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004348 context.verify_mode = ssl.CERT_REQUIRED
Christian Heimesbd5c7d22018-01-20 15:16:30 +01004349 context.load_verify_locations(SIGNING_CA)
4350 context.load_cert_chain(SIGNED_CERTFILE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004351 server = ThreadedEchoServer(context=context, chatty=False)
4352 with server:
4353 with context.wrap_socket(socket.socket()) as s:
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004354 s.connect((HOST, server.port))
Hai Shia7f5d932020-08-04 00:41:24 +08004355 with open(os_helper.TESTFN, 'rb') as file:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004356 s.sendfile(file)
4357 self.assertEqual(s.recv(1024), TEST_DATA)
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004358
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004359 def test_session(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004360 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004361 # TODO: sessions aren't compatible with TLSv1.3 yet
4362 client_context.options |= ssl.OP_NO_TLSv1_3
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004363
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004364 # first connection without session
Christian Heimesa170fa12017-09-15 20:27:30 +02004365 stats = server_params_test(client_context, server_context,
4366 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004367 session = stats['session']
4368 self.assertTrue(session.id)
4369 self.assertGreater(session.time, 0)
4370 self.assertGreater(session.timeout, 0)
4371 self.assertTrue(session.has_ticket)
4372 if ssl.OPENSSL_VERSION_INFO > (1, 0, 1):
4373 self.assertGreater(session.ticket_lifetime_hint, 0)
4374 self.assertFalse(stats['session_reused'])
4375 sess_stat = server_context.session_stats()
4376 self.assertEqual(sess_stat['accept'], 1)
4377 self.assertEqual(sess_stat['hits'], 0)
Giampaolo Rodola'915d1412014-06-11 03:54:30 +02004378
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004379 # reuse session
Christian Heimesa170fa12017-09-15 20:27:30 +02004380 stats = server_params_test(client_context, server_context,
4381 session=session, sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004382 sess_stat = server_context.session_stats()
4383 self.assertEqual(sess_stat['accept'], 2)
4384 self.assertEqual(sess_stat['hits'], 1)
4385 self.assertTrue(stats['session_reused'])
4386 session2 = stats['session']
4387 self.assertEqual(session2.id, session.id)
4388 self.assertEqual(session2, session)
4389 self.assertIsNot(session2, session)
4390 self.assertGreaterEqual(session2.time, session.time)
4391 self.assertGreaterEqual(session2.timeout, session.timeout)
Christian Heimes99a65702016-09-10 23:44:53 +02004392
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004393 # another one without session
Christian Heimesa170fa12017-09-15 20:27:30 +02004394 stats = server_params_test(client_context, server_context,
4395 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004396 self.assertFalse(stats['session_reused'])
4397 session3 = stats['session']
4398 self.assertNotEqual(session3.id, session.id)
4399 self.assertNotEqual(session3, session)
4400 sess_stat = server_context.session_stats()
4401 self.assertEqual(sess_stat['accept'], 3)
4402 self.assertEqual(sess_stat['hits'], 1)
Christian Heimes99a65702016-09-10 23:44:53 +02004403
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004404 # reuse session again
Christian Heimesa170fa12017-09-15 20:27:30 +02004405 stats = server_params_test(client_context, server_context,
4406 session=session, sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004407 self.assertTrue(stats['session_reused'])
4408 session4 = stats['session']
4409 self.assertEqual(session4.id, session.id)
4410 self.assertEqual(session4, session)
4411 self.assertGreaterEqual(session4.time, session.time)
4412 self.assertGreaterEqual(session4.timeout, session.timeout)
4413 sess_stat = server_context.session_stats()
4414 self.assertEqual(sess_stat['accept'], 4)
4415 self.assertEqual(sess_stat['hits'], 2)
Christian Heimes99a65702016-09-10 23:44:53 +02004416
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004417 def test_session_handling(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004418 client_context, server_context, hostname = testing_context()
4419 client_context2, _, _ = testing_context()
Christian Heimes99a65702016-09-10 23:44:53 +02004420
Christian Heimes05d9fe32018-02-27 08:55:39 +01004421 # TODO: session reuse does not work with TLSv1.3
Christian Heimesa170fa12017-09-15 20:27:30 +02004422 client_context.options |= ssl.OP_NO_TLSv1_3
4423 client_context2.options |= ssl.OP_NO_TLSv1_3
Christian Heimescb5b68a2017-09-07 18:07:00 -07004424
Christian Heimesa170fa12017-09-15 20:27:30 +02004425 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004426 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02004427 with client_context.wrap_socket(socket.socket(),
4428 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004429 # session is None before handshake
4430 self.assertEqual(s.session, None)
4431 self.assertEqual(s.session_reused, None)
4432 s.connect((HOST, server.port))
4433 session = s.session
4434 self.assertTrue(session)
4435 with self.assertRaises(TypeError) as e:
4436 s.session = object
Ned Deily4531ec72018-06-11 20:26:28 -04004437 self.assertEqual(str(e.exception), 'Value is not a SSLSession.')
Christian Heimes99a65702016-09-10 23:44:53 +02004438
Christian Heimesa170fa12017-09-15 20:27:30 +02004439 with client_context.wrap_socket(socket.socket(),
4440 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004441 s.connect((HOST, server.port))
4442 # cannot set session after handshake
4443 with self.assertRaises(ValueError) as e:
4444 s.session = session
4445 self.assertEqual(str(e.exception),
4446 'Cannot set session after handshake.')
Christian Heimes99a65702016-09-10 23:44:53 +02004447
Christian Heimesa170fa12017-09-15 20:27:30 +02004448 with client_context.wrap_socket(socket.socket(),
4449 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004450 # can set session before handshake and before the
4451 # connection was established
4452 s.session = session
4453 s.connect((HOST, server.port))
4454 self.assertEqual(s.session.id, session.id)
4455 self.assertEqual(s.session, session)
4456 self.assertEqual(s.session_reused, True)
Christian Heimes99a65702016-09-10 23:44:53 +02004457
Christian Heimesa170fa12017-09-15 20:27:30 +02004458 with client_context2.wrap_socket(socket.socket(),
4459 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004460 # cannot re-use session with a different SSLContext
4461 with self.assertRaises(ValueError) as e:
Christian Heimes99a65702016-09-10 23:44:53 +02004462 s.session = session
4463 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004464 self.assertEqual(str(e.exception),
4465 'Session refers to a different SSLContext.')
Christian Heimes99a65702016-09-10 23:44:53 +02004466
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01004467
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02004468@unittest.skipUnless(has_tls_version('TLSv1_3'), "Test needs TLS 1.3")
Christian Heimes9fb051f2018-09-23 08:32:31 +02004469class TestPostHandshakeAuth(unittest.TestCase):
4470 def test_pha_setter(self):
4471 protocols = [
4472 ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS_SERVER, ssl.PROTOCOL_TLS_CLIENT
4473 ]
4474 for protocol in protocols:
4475 ctx = ssl.SSLContext(protocol)
4476 self.assertEqual(ctx.post_handshake_auth, False)
4477
4478 ctx.post_handshake_auth = True
4479 self.assertEqual(ctx.post_handshake_auth, True)
4480
4481 ctx.verify_mode = ssl.CERT_REQUIRED
4482 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
4483 self.assertEqual(ctx.post_handshake_auth, True)
4484
4485 ctx.post_handshake_auth = False
4486 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
4487 self.assertEqual(ctx.post_handshake_auth, False)
4488
4489 ctx.verify_mode = ssl.CERT_OPTIONAL
4490 ctx.post_handshake_auth = True
4491 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
4492 self.assertEqual(ctx.post_handshake_auth, True)
4493
4494 def test_pha_required(self):
4495 client_context, server_context, hostname = testing_context()
4496 server_context.post_handshake_auth = True
4497 server_context.verify_mode = ssl.CERT_REQUIRED
4498 client_context.post_handshake_auth = True
4499 client_context.load_cert_chain(SIGNED_CERTFILE)
4500
4501 server = ThreadedEchoServer(context=server_context, chatty=False)
4502 with server:
4503 with client_context.wrap_socket(socket.socket(),
4504 server_hostname=hostname) as s:
4505 s.connect((HOST, server.port))
4506 s.write(b'HASCERT')
4507 self.assertEqual(s.recv(1024), b'FALSE\n')
4508 s.write(b'PHA')
4509 self.assertEqual(s.recv(1024), b'OK\n')
4510 s.write(b'HASCERT')
4511 self.assertEqual(s.recv(1024), b'TRUE\n')
4512 # PHA method just returns true when cert is already available
4513 s.write(b'PHA')
4514 self.assertEqual(s.recv(1024), b'OK\n')
4515 s.write(b'GETCERT')
4516 cert_text = s.recv(4096).decode('us-ascii')
4517 self.assertIn('Python Software Foundation CA', cert_text)
4518
4519 def test_pha_required_nocert(self):
4520 client_context, server_context, hostname = testing_context()
4521 server_context.post_handshake_auth = True
4522 server_context.verify_mode = ssl.CERT_REQUIRED
4523 client_context.post_handshake_auth = True
4524
Victor Stinner73ea5462019-07-09 14:33:49 +02004525 # Ignore expected SSLError in ConnectionHandler of ThreadedEchoServer
4526 # (it is only raised sometimes on Windows)
Hai Shie80697d2020-05-28 06:10:27 +08004527 with threading_helper.catch_threading_exception() as cm:
Victor Stinner73ea5462019-07-09 14:33:49 +02004528 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 s.write(b'PHA')
4534 # receive CertificateRequest
4535 self.assertEqual(s.recv(1024), b'OK\n')
4536 # send empty Certificate + Finish
4537 s.write(b'HASCERT')
4538 # receive alert
4539 with self.assertRaisesRegex(
4540 ssl.SSLError,
4541 'tlsv13 alert certificate required'):
4542 s.recv(1024)
Christian Heimes9fb051f2018-09-23 08:32:31 +02004543
4544 def test_pha_optional(self):
4545 if support.verbose:
4546 sys.stdout.write("\n")
4547
4548 client_context, server_context, hostname = testing_context()
4549 server_context.post_handshake_auth = True
4550 server_context.verify_mode = ssl.CERT_REQUIRED
4551 client_context.post_handshake_auth = True
4552 client_context.load_cert_chain(SIGNED_CERTFILE)
4553
4554 # check CERT_OPTIONAL
4555 server_context.verify_mode = ssl.CERT_OPTIONAL
4556 server = ThreadedEchoServer(context=server_context, chatty=False)
4557 with server:
4558 with client_context.wrap_socket(socket.socket(),
4559 server_hostname=hostname) as s:
4560 s.connect((HOST, server.port))
4561 s.write(b'HASCERT')
4562 self.assertEqual(s.recv(1024), b'FALSE\n')
4563 s.write(b'PHA')
4564 self.assertEqual(s.recv(1024), b'OK\n')
4565 s.write(b'HASCERT')
4566 self.assertEqual(s.recv(1024), b'TRUE\n')
4567
4568 def test_pha_optional_nocert(self):
4569 if support.verbose:
4570 sys.stdout.write("\n")
4571
4572 client_context, server_context, hostname = testing_context()
4573 server_context.post_handshake_auth = True
4574 server_context.verify_mode = ssl.CERT_OPTIONAL
4575 client_context.post_handshake_auth = True
4576
4577 server = ThreadedEchoServer(context=server_context, chatty=False)
4578 with server:
4579 with client_context.wrap_socket(socket.socket(),
4580 server_hostname=hostname) as s:
4581 s.connect((HOST, server.port))
4582 s.write(b'HASCERT')
4583 self.assertEqual(s.recv(1024), b'FALSE\n')
4584 s.write(b'PHA')
4585 self.assertEqual(s.recv(1024), b'OK\n')
penguindustin96466302019-05-06 14:57:17 -04004586 # optional doesn't fail when client does not have a cert
Christian Heimes9fb051f2018-09-23 08:32:31 +02004587 s.write(b'HASCERT')
4588 self.assertEqual(s.recv(1024), b'FALSE\n')
4589
4590 def test_pha_no_pha_client(self):
4591 client_context, server_context, hostname = testing_context()
4592 server_context.post_handshake_auth = True
4593 server_context.verify_mode = ssl.CERT_REQUIRED
4594 client_context.load_cert_chain(SIGNED_CERTFILE)
4595
4596 server = ThreadedEchoServer(context=server_context, chatty=False)
4597 with server:
4598 with client_context.wrap_socket(socket.socket(),
4599 server_hostname=hostname) as s:
4600 s.connect((HOST, server.port))
4601 with self.assertRaisesRegex(ssl.SSLError, 'not server'):
4602 s.verify_client_post_handshake()
4603 s.write(b'PHA')
4604 self.assertIn(b'extension not received', s.recv(1024))
4605
4606 def test_pha_no_pha_server(self):
4607 # server doesn't have PHA enabled, cert is requested in handshake
4608 client_context, server_context, hostname = testing_context()
4609 server_context.verify_mode = ssl.CERT_REQUIRED
4610 client_context.post_handshake_auth = True
4611 client_context.load_cert_chain(SIGNED_CERTFILE)
4612
4613 server = ThreadedEchoServer(context=server_context, chatty=False)
4614 with server:
4615 with client_context.wrap_socket(socket.socket(),
4616 server_hostname=hostname) as s:
4617 s.connect((HOST, server.port))
4618 s.write(b'HASCERT')
4619 self.assertEqual(s.recv(1024), b'TRUE\n')
4620 # PHA doesn't fail if there is already a cert
4621 s.write(b'PHA')
4622 self.assertEqual(s.recv(1024), b'OK\n')
4623 s.write(b'HASCERT')
4624 self.assertEqual(s.recv(1024), b'TRUE\n')
4625
4626 def test_pha_not_tls13(self):
4627 # TLS 1.2
4628 client_context, server_context, hostname = testing_context()
4629 server_context.verify_mode = ssl.CERT_REQUIRED
4630 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
4631 client_context.post_handshake_auth = True
4632 client_context.load_cert_chain(SIGNED_CERTFILE)
4633
4634 server = ThreadedEchoServer(context=server_context, chatty=False)
4635 with server:
4636 with client_context.wrap_socket(socket.socket(),
4637 server_hostname=hostname) as s:
4638 s.connect((HOST, server.port))
4639 # PHA fails for TLS != 1.3
4640 s.write(b'PHA')
4641 self.assertIn(b'WRONG_SSL_VERSION', s.recv(1024))
4642
Christian Heimesf0f59302019-07-01 08:29:17 +02004643 def test_bpo37428_pha_cert_none(self):
4644 # verify that post_handshake_auth does not implicitly enable cert
4645 # validation.
4646 hostname = SIGNED_CERTFILE_HOSTNAME
4647 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4648 client_context.post_handshake_auth = True
4649 client_context.load_cert_chain(SIGNED_CERTFILE)
4650 # no cert validation and CA on client side
4651 client_context.check_hostname = False
4652 client_context.verify_mode = ssl.CERT_NONE
4653
4654 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
4655 server_context.load_cert_chain(SIGNED_CERTFILE)
4656 server_context.load_verify_locations(SIGNING_CA)
4657 server_context.post_handshake_auth = True
4658 server_context.verify_mode = ssl.CERT_REQUIRED
4659
4660 server = ThreadedEchoServer(context=server_context, chatty=False)
4661 with server:
4662 with client_context.wrap_socket(socket.socket(),
4663 server_hostname=hostname) as s:
4664 s.connect((HOST, server.port))
4665 s.write(b'HASCERT')
4666 self.assertEqual(s.recv(1024), b'FALSE\n')
4667 s.write(b'PHA')
4668 self.assertEqual(s.recv(1024), b'OK\n')
4669 s.write(b'HASCERT')
4670 self.assertEqual(s.recv(1024), b'TRUE\n')
4671 # server cert has not been validated
4672 self.assertEqual(s.getpeercert(), {})
4673
Christian Heimes9fb051f2018-09-23 08:32:31 +02004674
Christian Heimesc7f70692019-05-31 11:44:05 +02004675HAS_KEYLOG = hasattr(ssl.SSLContext, 'keylog_filename')
4676requires_keylog = unittest.skipUnless(
4677 HAS_KEYLOG, 'test requires OpenSSL 1.1.1 with keylog callback')
4678
4679class TestSSLDebug(unittest.TestCase):
4680
Hai Shia7f5d932020-08-04 00:41:24 +08004681 def keylog_lines(self, fname=os_helper.TESTFN):
Christian Heimesc7f70692019-05-31 11:44:05 +02004682 with open(fname) as f:
4683 return len(list(f))
4684
4685 @requires_keylog
Paul Monsonf3550692019-06-19 13:09:54 -07004686 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004687 def test_keylog_defaults(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004688 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004689 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4690 self.assertEqual(ctx.keylog_filename, None)
4691
Hai Shia7f5d932020-08-04 00:41:24 +08004692 self.assertFalse(os.path.isfile(os_helper.TESTFN))
4693 ctx.keylog_filename = os_helper.TESTFN
4694 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
4695 self.assertTrue(os.path.isfile(os_helper.TESTFN))
Christian Heimesc7f70692019-05-31 11:44:05 +02004696 self.assertEqual(self.keylog_lines(), 1)
4697
4698 ctx.keylog_filename = None
4699 self.assertEqual(ctx.keylog_filename, None)
4700
4701 with self.assertRaises((IsADirectoryError, PermissionError)):
4702 # Windows raises PermissionError
4703 ctx.keylog_filename = os.path.dirname(
Hai Shia7f5d932020-08-04 00:41:24 +08004704 os.path.abspath(os_helper.TESTFN))
Christian Heimesc7f70692019-05-31 11:44:05 +02004705
4706 with self.assertRaises(TypeError):
4707 ctx.keylog_filename = 1
4708
4709 @requires_keylog
Paul Monsonf3550692019-06-19 13:09:54 -07004710 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004711 def test_keylog_filename(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004712 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004713 client_context, server_context, hostname = testing_context()
4714
Hai Shia7f5d932020-08-04 00:41:24 +08004715 client_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004716 server = ThreadedEchoServer(context=server_context, chatty=False)
4717 with server:
4718 with client_context.wrap_socket(socket.socket(),
4719 server_hostname=hostname) as s:
4720 s.connect((HOST, server.port))
4721 # header, 5 lines for TLS 1.3
4722 self.assertEqual(self.keylog_lines(), 6)
4723
4724 client_context.keylog_filename = None
Hai Shia7f5d932020-08-04 00:41:24 +08004725 server_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004726 server = ThreadedEchoServer(context=server_context, chatty=False)
4727 with server:
4728 with client_context.wrap_socket(socket.socket(),
4729 server_hostname=hostname) as s:
4730 s.connect((HOST, server.port))
4731 self.assertGreaterEqual(self.keylog_lines(), 11)
4732
Hai Shia7f5d932020-08-04 00:41:24 +08004733 client_context.keylog_filename = os_helper.TESTFN
4734 server_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004735 server = ThreadedEchoServer(context=server_context, chatty=False)
4736 with server:
4737 with client_context.wrap_socket(socket.socket(),
4738 server_hostname=hostname) as s:
4739 s.connect((HOST, server.port))
4740 self.assertGreaterEqual(self.keylog_lines(), 21)
4741
4742 client_context.keylog_filename = None
4743 server_context.keylog_filename = None
4744
4745 @requires_keylog
4746 @unittest.skipIf(sys.flags.ignore_environment,
4747 "test is not compatible with ignore_environment")
Paul Monsonf3550692019-06-19 13:09:54 -07004748 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004749 def test_keylog_env(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004750 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004751 with unittest.mock.patch.dict(os.environ):
Hai Shia7f5d932020-08-04 00:41:24 +08004752 os.environ['SSLKEYLOGFILE'] = os_helper.TESTFN
4753 self.assertEqual(os.environ['SSLKEYLOGFILE'], os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004754
4755 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4756 self.assertEqual(ctx.keylog_filename, None)
4757
4758 ctx = ssl.create_default_context()
Hai Shia7f5d932020-08-04 00:41:24 +08004759 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004760
4761 ctx = ssl._create_stdlib_context()
Hai Shia7f5d932020-08-04 00:41:24 +08004762 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004763
4764 def test_msg_callback(self):
4765 client_context, server_context, hostname = testing_context()
4766
4767 def msg_cb(conn, direction, version, content_type, msg_type, data):
4768 pass
4769
4770 self.assertIs(client_context._msg_callback, None)
4771 client_context._msg_callback = msg_cb
4772 self.assertIs(client_context._msg_callback, msg_cb)
4773 with self.assertRaises(TypeError):
4774 client_context._msg_callback = object()
4775
4776 def test_msg_callback_tls12(self):
4777 client_context, server_context, hostname = testing_context()
4778 client_context.options |= ssl.OP_NO_TLSv1_3
4779
4780 msg = []
4781
4782 def msg_cb(conn, direction, version, content_type, msg_type, data):
4783 self.assertIsInstance(conn, ssl.SSLSocket)
4784 self.assertIsInstance(data, bytes)
4785 self.assertIn(direction, {'read', 'write'})
4786 msg.append((direction, version, content_type, msg_type))
4787
4788 client_context._msg_callback = msg_cb
4789
4790 server = ThreadedEchoServer(context=server_context, chatty=False)
4791 with server:
4792 with client_context.wrap_socket(socket.socket(),
4793 server_hostname=hostname) as s:
4794 s.connect((HOST, server.port))
4795
Christian Heimese35d1ba2019-06-03 20:40:15 +02004796 self.assertIn(
Christian Heimesc7f70692019-05-31 11:44:05 +02004797 ("read", TLSVersion.TLSv1_2, _TLSContentType.HANDSHAKE,
4798 _TLSMessageType.SERVER_KEY_EXCHANGE),
Christian Heimese35d1ba2019-06-03 20:40:15 +02004799 msg
4800 )
4801 self.assertIn(
Christian Heimesc7f70692019-05-31 11:44:05 +02004802 ("write", TLSVersion.TLSv1_2, _TLSContentType.CHANGE_CIPHER_SPEC,
4803 _TLSMessageType.CHANGE_CIPHER_SPEC),
Christian Heimese35d1ba2019-06-03 20:40:15 +02004804 msg
4805 )
Christian Heimesc7f70692019-05-31 11:44:05 +02004806
Christian Heimes77cde502021-03-21 16:13:09 +01004807 def test_msg_callback_deadlock_bpo43577(self):
4808 client_context, server_context, hostname = testing_context()
4809 server_context2 = testing_context()[1]
4810
4811 def msg_cb(conn, direction, version, content_type, msg_type, data):
4812 pass
4813
4814 def sni_cb(sock, servername, ctx):
4815 sock.context = server_context2
4816
4817 server_context._msg_callback = msg_cb
4818 server_context.sni_callback = sni_cb
4819
4820 server = ThreadedEchoServer(context=server_context, chatty=False)
4821 with server:
4822 with client_context.wrap_socket(socket.socket(),
4823 server_hostname=hostname) as s:
4824 s.connect((HOST, server.port))
4825 with client_context.wrap_socket(socket.socket(),
4826 server_hostname=hostname) as s:
4827 s.connect((HOST, server.port))
4828
Christian Heimesc7f70692019-05-31 11:44:05 +02004829
Thomas Woutersed03b412007-08-28 21:37:11 +00004830def test_main(verbose=False):
Antoine Pitrou15cee622010-08-04 16:45:21 +00004831 if support.verbose:
4832 plats = {
Antoine Pitrou15cee622010-08-04 16:45:21 +00004833 'Mac': platform.mac_ver,
4834 'Windows': platform.win32_ver,
4835 }
Petr Viktorin8b94b412018-05-16 11:51:18 -04004836 for name, func in plats.items():
4837 plat = func()
4838 if plat and plat[0]:
4839 plat = '%s %r' % (name, plat)
4840 break
4841 else:
4842 plat = repr(platform.platform())
Antoine Pitrou15cee622010-08-04 16:45:21 +00004843 print("test_ssl: testing with %r %r" %
4844 (ssl.OPENSSL_VERSION, ssl.OPENSSL_VERSION_INFO))
4845 print(" under %s" % plat)
Antoine Pitroud5323212010-10-22 18:19:07 +00004846 print(" HAS_SNI = %r" % ssl.HAS_SNI)
Antoine Pitrou609ef012013-03-29 18:09:06 +01004847 print(" OP_ALL = 0x%8x" % ssl.OP_ALL)
4848 try:
4849 print(" OP_NO_TLSv1_1 = 0x%8x" % ssl.OP_NO_TLSv1_1)
4850 except AttributeError:
4851 pass
Antoine Pitrou15cee622010-08-04 16:45:21 +00004852
Antoine Pitrou152efa22010-05-16 18:19:27 +00004853 for filename in [
Martin Panter3840b2a2016-03-27 01:53:46 +00004854 CERTFILE, BYTES_CERTFILE,
Antoine Pitrou152efa22010-05-16 18:19:27 +00004855 ONLYCERT, ONLYKEY, BYTES_ONLYCERT, BYTES_ONLYKEY,
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004856 SIGNED_CERTFILE, SIGNED_CERTFILE2, SIGNING_CA,
Antoine Pitrou152efa22010-05-16 18:19:27 +00004857 BADCERT, BADKEY, EMPTYCERT]:
4858 if not os.path.exists(filename):
4859 raise support.TestFailed("Can't read certificate file %r" % filename)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004860
Martin Panter3840b2a2016-03-27 01:53:46 +00004861 tests = [
4862 ContextTests, BasicSocketTests, SSLErrorTests, MemoryBIOTests,
Christian Heimes9d50ab52018-02-27 10:17:30 +01004863 SSLObjectTests, SimpleBackgroundTests, ThreadedTests,
Christian Heimesc7f70692019-05-31 11:44:05 +02004864 TestPostHandshakeAuth, TestSSLDebug
Martin Panter3840b2a2016-03-27 01:53:46 +00004865 ]
Thomas Woutersed03b412007-08-28 21:37:11 +00004866
Benjamin Petersonee8712c2008-05-20 21:35:26 +00004867 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00004868 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00004869
Hai Shie80697d2020-05-28 06:10:27 +08004870 thread_info = threading_helper.threading_setup()
Antoine Pitrou480a1242010-04-28 21:37:09 +00004871 try:
4872 support.run_unittest(*tests)
4873 finally:
Hai Shie80697d2020-05-28 06:10:27 +08004874 threading_helper.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00004875
4876if __name__ == "__main__":
4877 test_main()