blob: 140aecc712738e4f9f808677ba7429774b8e2244 [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 Heimese6dac002018-08-30 07:25:49 +0200113 'notAfter': 'Jul 7 14:23:16 2028 GMT',
114 '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")
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100134
Martin Panter3d81d932016-01-14 09:36:00 +0000135REMOTE_HOST = "self-signed.pythontest.net"
Antoine Pitrou152efa22010-05-16 18:19:27 +0000136
137EMPTYCERT = data_file("nullcert.pem")
138BADCERT = data_file("badcert.pem")
Martin Panter407b62f2016-01-30 03:41:43 +0000139NONEXISTINGCERT = data_file("XXXnonexisting.pem")
Antoine Pitrou152efa22010-05-16 18:19:27 +0000140BADKEY = data_file("badkey.pem")
Antoine Pitroud8c347a2011-10-01 19:20:25 +0200141NOKIACERT = data_file("nokia.pem")
Christian Heimes824f7f32013-08-17 00:54:47 +0200142NULLBYTECERT = data_file("nullbytecert.pem")
Christian Heimesa37f5242019-01-15 23:47:42 +0100143TALOS_INVALID_CRLDP = data_file("talos-2019-0758.pem")
Antoine Pitrou152efa22010-05-16 18:19:27 +0000144
Christian Heimes88bfd0b2018-08-14 12:54:19 +0200145DHFILE = data_file("ffdh3072.pem")
Antoine Pitrou0e576f12011-12-22 10:03:38 +0100146BYTES_DHFILE = os.fsencode(DHFILE)
Thomas Woutersed03b412007-08-28 21:37:11 +0000147
Christian Heimes358cfd42016-09-10 22:43:48 +0200148# Not defined in all versions of OpenSSL
149OP_NO_COMPRESSION = getattr(ssl, "OP_NO_COMPRESSION", 0)
150OP_SINGLE_DH_USE = getattr(ssl, "OP_SINGLE_DH_USE", 0)
151OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0)
152OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0)
Christian Heimes05d9fe32018-02-27 08:55:39 +0100153OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0)
Christian Heimes6f37ebc2021-04-09 17:59:21 +0200154OP_IGNORE_UNEXPECTED_EOF = getattr(ssl, "OP_IGNORE_UNEXPECTED_EOF", 0)
Christian Heimes358cfd42016-09-10 22:43:48 +0200155
Christian Heimesf6c6b582021-03-18 23:06:50 +0100156# Ubuntu has patched OpenSSL and changed behavior of security level 2
157# see https://bugs.python.org/issue41561#msg389003
158def is_ubuntu():
159 try:
160 # Assume that any references of "ubuntu" implies Ubuntu-like distro
161 # The workaround is not required for 18.04, but doesn't hurt either.
162 with open("/etc/os-release", encoding="utf-8") as f:
163 return "ubuntu" in f.read()
164 except FileNotFoundError:
165 return False
166
167if is_ubuntu():
168 def seclevel_workaround(*ctxs):
169 """"Lower security level to '1' and allow all ciphers for TLS 1.0/1"""
170 for ctx in ctxs:
Christian Heimes34477502021-04-12 12:00:38 +0200171 if (
172 hasattr(ctx, "minimum_version") and
173 ctx.minimum_version <= ssl.TLSVersion.TLSv1_1
174 ):
Christian Heimesf6c6b582021-03-18 23:06:50 +0100175 ctx.set_ciphers("@SECLEVEL=1:ALL")
176else:
177 def seclevel_workaround(*ctxs):
178 pass
179
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100180
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200181def has_tls_protocol(protocol):
182 """Check if a TLS protocol is available and enabled
183
184 :param protocol: enum ssl._SSLMethod member or name
185 :return: bool
186 """
187 if isinstance(protocol, str):
188 assert protocol.startswith('PROTOCOL_')
189 protocol = getattr(ssl, protocol, None)
190 if protocol is None:
191 return False
192 if protocol in {
193 ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS_SERVER,
194 ssl.PROTOCOL_TLS_CLIENT
195 }:
196 # auto-negotiate protocols are always available
197 return True
198 name = protocol.name
199 return has_tls_version(name[len('PROTOCOL_'):])
200
201
202@functools.lru_cache
203def has_tls_version(version):
204 """Check if a TLS/SSL version is enabled
205
206 :param version: TLS version name or ssl.TLSVersion member
207 :return: bool
208 """
209 if version == "SSLv2":
210 # never supported and not even in TLSVersion enum
211 return False
212
213 if isinstance(version, str):
214 version = ssl.TLSVersion.__members__[version]
215
216 # check compile time flags like ssl.HAS_TLSv1_2
217 if not getattr(ssl, f'HAS_{version.name}'):
218 return False
219
Christian Heimes5151d642021-04-09 15:43:06 +0200220 if IS_OPENSSL_3_0_0 and version < ssl.TLSVersion.TLSv1_2:
221 # bpo43791: 3.0.0-alpha14 fails with TLSV1_ALERT_INTERNAL_ERROR
222 return False
223
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200224 # check runtime and dynamic crypto policy settings. A TLS version may
225 # be compiled in but disabled by a policy or config option.
226 ctx = ssl.SSLContext()
227 if (
Christian Heimes9f772682019-09-26 18:23:17 +0200228 hasattr(ctx, 'minimum_version') and
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200229 ctx.minimum_version != ssl.TLSVersion.MINIMUM_SUPPORTED and
230 version < ctx.minimum_version
231 ):
232 return False
233 if (
Christian Heimes9f772682019-09-26 18:23:17 +0200234 hasattr(ctx, 'maximum_version') and
Christian Heimesdf6ac7e2019-09-26 17:02:59 +0200235 ctx.maximum_version != ssl.TLSVersion.MAXIMUM_SUPPORTED and
236 version > ctx.maximum_version
237 ):
238 return False
239
240 return True
241
242
243def requires_tls_version(version):
244 """Decorator to skip tests when a required TLS version is not available
245
246 :param version: TLS version name or ssl.TLSVersion member
247 :return:
248 """
249 def decorator(func):
250 @functools.wraps(func)
251 def wrapper(*args, **kw):
252 if not has_tls_version(version):
253 raise unittest.SkipTest(f"{version} is not available.")
254 else:
255 return func(*args, **kw)
256 return wrapper
257 return decorator
258
259
260requires_minimum_version = unittest.skipUnless(
261 hasattr(ssl.SSLContext, 'minimum_version'),
262 "required OpenSSL >= 1.1.0g"
263)
264
265
Thomas Woutersed03b412007-08-28 21:37:11 +0000266def handle_error(prefix):
267 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000268 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000269 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +0000270
Antoine Pitroub5218772010-05-21 09:56:06 +0000271def can_clear_options():
272 # 0.9.8m or higher
Antoine Pitroub9ac25d2011-07-08 18:47:06 +0200273 return ssl._OPENSSL_API_VERSION >= (0, 9, 8, 13, 15)
Antoine Pitroub5218772010-05-21 09:56:06 +0000274
275def no_sslv2_implies_sslv3_hello():
276 # 0.9.7h or higher
277 return ssl.OPENSSL_VERSION_INFO >= (0, 9, 7, 8, 15)
278
Christian Heimes2427b502013-11-23 11:24:32 +0100279def have_verify_flags():
280 # 0.9.8 or higher
281 return ssl.OPENSSL_VERSION_INFO >= (0, 9, 8, 0, 15)
282
Christian Heimesb7b92252018-02-25 09:49:31 +0100283def _have_secp_curves():
284 if not ssl.HAS_ECDH:
285 return False
286 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
287 try:
288 ctx.set_ecdh_curve("secp384r1")
289 except ValueError:
290 return False
291 else:
292 return True
293
294
295HAVE_SECP_CURVES = _have_secp_curves()
296
297
Antoine Pitrouc695c952014-04-28 20:57:36 +0200298def utc_offset(): #NOTE: ignore issues like #1647654
299 # local time = utc time + utc offset
300 if time.daylight and time.localtime().tm_isdst > 0:
301 return -time.altzone # seconds
302 return -time.timezone
303
Christian Heimes9424bb42013-06-17 15:32:57 +0200304def asn1time(cert_time):
305 # Some versions of OpenSSL ignore seconds, see #18207
306 # 0.9.8.i
307 if ssl._OPENSSL_API_VERSION == (0, 9, 8, 9, 15):
308 fmt = "%b %d %H:%M:%S %Y GMT"
309 dt = datetime.datetime.strptime(cert_time, fmt)
310 dt = dt.replace(second=0)
311 cert_time = dt.strftime(fmt)
312 # %d adds leading zero but ASN1_TIME_print() uses leading space
313 if cert_time[4] == "0":
314 cert_time = cert_time[:4] + " " + cert_time[5:]
315
316 return cert_time
Thomas Woutersed03b412007-08-28 21:37:11 +0000317
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +0100318needs_sni = unittest.skipUnless(ssl.HAS_SNI, "SNI support needed for this test")
319
Antoine Pitrou23df4832010-08-04 17:14:06 +0000320
Christian Heimesd0486372016-09-10 23:23:33 +0200321def test_wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLS, *,
322 cert_reqs=ssl.CERT_NONE, ca_certs=None,
323 ciphers=None, certfile=None, keyfile=None,
324 **kwargs):
325 context = ssl.SSLContext(ssl_version)
326 if cert_reqs is not None:
Christian Heimesa170fa12017-09-15 20:27:30 +0200327 if cert_reqs == ssl.CERT_NONE:
328 context.check_hostname = False
Christian Heimesd0486372016-09-10 23:23:33 +0200329 context.verify_mode = cert_reqs
330 if ca_certs is not None:
331 context.load_verify_locations(ca_certs)
332 if certfile is not None or keyfile is not None:
333 context.load_cert_chain(certfile, keyfile)
334 if ciphers is not None:
335 context.set_ciphers(ciphers)
336 return context.wrap_socket(sock, **kwargs)
337
Christian Heimesa170fa12017-09-15 20:27:30 +0200338
339def testing_context(server_cert=SIGNED_CERTFILE):
340 """Create context
341
342 client_context, server_context, hostname = testing_context()
343 """
344 if server_cert == SIGNED_CERTFILE:
345 hostname = SIGNED_CERTFILE_HOSTNAME
346 elif server_cert == SIGNED_CERTFILE2:
347 hostname = SIGNED_CERTFILE2_HOSTNAME
348 else:
349 raise ValueError(server_cert)
350
351 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
352 client_context.load_verify_locations(SIGNING_CA)
353
354 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
355 server_context.load_cert_chain(server_cert)
Christian Heimes9fb051f2018-09-23 08:32:31 +0200356 server_context.load_verify_locations(SIGNING_CA)
Christian Heimesa170fa12017-09-15 20:27:30 +0200357
358 return client_context, server_context, hostname
359
360
Antoine Pitrou152efa22010-05-16 18:19:27 +0000361class BasicSocketTests(unittest.TestCase):
Thomas Woutersed03b412007-08-28 21:37:11 +0000362
Antoine Pitrou480a1242010-04-28 21:37:09 +0000363 def test_constants(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000364 ssl.CERT_NONE
365 ssl.CERT_OPTIONAL
366 ssl.CERT_REQUIRED
Antoine Pitrou6db49442011-12-19 13:27:11 +0100367 ssl.OP_CIPHER_SERVER_PREFERENCE
Antoine Pitrou0e576f12011-12-22 10:03:38 +0100368 ssl.OP_SINGLE_DH_USE
Antoine Pitrouc135fa42012-02-19 21:22:39 +0100369 if ssl.HAS_ECDH:
370 ssl.OP_SINGLE_ECDH_USE
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +0100371 if ssl.OPENSSL_VERSION_INFO >= (1, 0):
372 ssl.OP_NO_COMPRESSION
Antoine Pitroud5323212010-10-22 18:19:07 +0000373 self.assertIn(ssl.HAS_SNI, {True, False})
Antoine Pitrou501da612011-12-21 09:27:41 +0100374 self.assertIn(ssl.HAS_ECDH, {True, False})
Christian Heimescb5b68a2017-09-07 18:07:00 -0700375 ssl.OP_NO_SSLv2
376 ssl.OP_NO_SSLv3
377 ssl.OP_NO_TLSv1
378 ssl.OP_NO_TLSv1_3
379 if ssl.OPENSSL_VERSION_INFO >= (1, 0, 1):
380 ssl.OP_NO_TLSv1_1
381 ssl.OP_NO_TLSv1_2
Christian Heimesa170fa12017-09-15 20:27:30 +0200382 self.assertEqual(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv23)
Thomas Woutersed03b412007-08-28 21:37:11 +0000383
Christian Heimes9d50ab52018-02-27 10:17:30 +0100384 def test_private_init(self):
385 with self.assertRaisesRegex(TypeError, "public constructor"):
386 with socket.socket() as s:
387 ssl.SSLSocket(s)
388
Antoine Pitrou172f0252014-04-18 20:33:08 +0200389 def test_str_for_enums(self):
390 # Make sure that the PROTOCOL_* constants have enum-like string
391 # reprs.
Christian Heimes598894f2016-09-05 23:19:05 +0200392 proto = ssl.PROTOCOL_TLS
Ethan Furmanb7751062021-03-30 21:17:26 -0700393 self.assertEqual(str(proto), 'PROTOCOL_TLS')
Antoine Pitrou172f0252014-04-18 20:33:08 +0200394 ctx = ssl.SSLContext(proto)
395 self.assertIs(ctx.protocol, proto)
396
Antoine Pitrou480a1242010-04-28 21:37:09 +0000397 def test_random(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000398 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000399 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000400 sys.stdout.write("\n RAND_status is %d (%s)\n"
401 % (v, (v and "sufficient randomness") or
402 "insufficient randomness"))
Victor Stinner99c8b162011-05-24 12:05:19 +0200403
404 data, is_cryptographic = ssl.RAND_pseudo_bytes(16)
405 self.assertEqual(len(data), 16)
406 self.assertEqual(is_cryptographic, v == 1)
407 if v:
408 data = ssl.RAND_bytes(16)
409 self.assertEqual(len(data), 16)
Victor Stinner2e2baa92011-05-25 11:15:16 +0200410 else:
411 self.assertRaises(ssl.SSLError, ssl.RAND_bytes, 16)
Victor Stinner99c8b162011-05-24 12:05:19 +0200412
Victor Stinner1e81a392013-12-19 16:47:04 +0100413 # negative num is invalid
414 self.assertRaises(ValueError, ssl.RAND_bytes, -5)
415 self.assertRaises(ValueError, ssl.RAND_pseudo_bytes, -5)
416
Victor Stinnerbeeb5122014-11-28 13:28:25 +0100417 if hasattr(ssl, 'RAND_egd'):
418 self.assertRaises(TypeError, ssl.RAND_egd, 1)
419 self.assertRaises(TypeError, ssl.RAND_egd, 'foo', 1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000420 ssl.RAND_add("this is a random string", 75.0)
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200421 ssl.RAND_add(b"this is a random bytes object", 75.0)
422 ssl.RAND_add(bytearray(b"this is a random bytearray object"), 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +0000423
pxinwr98a54172020-12-09 07:20:19 +0800424 @unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork')
Christian Heimesf77b4b22013-08-21 13:26:05 +0200425 def test_random_fork(self):
426 status = ssl.RAND_status()
427 if not status:
428 self.fail("OpenSSL's PRNG has insufficient randomness")
429
430 rfd, wfd = os.pipe()
431 pid = os.fork()
432 if pid == 0:
433 try:
434 os.close(rfd)
435 child_random = ssl.RAND_pseudo_bytes(16)[0]
436 self.assertEqual(len(child_random), 16)
437 os.write(wfd, child_random)
438 os.close(wfd)
439 except BaseException:
440 os._exit(1)
441 else:
442 os._exit(0)
443 else:
444 os.close(wfd)
445 self.addCleanup(os.close, rfd)
Victor Stinner278c1e12020-03-31 20:08:12 +0200446 support.wait_process(pid, exitcode=0)
Christian Heimesf77b4b22013-08-21 13:26:05 +0200447
448 child_random = os.read(rfd, 16)
449 self.assertEqual(len(child_random), 16)
450 parent_random = ssl.RAND_pseudo_bytes(16)[0]
451 self.assertEqual(len(parent_random), 16)
452
453 self.assertNotEqual(child_random, parent_random)
454
Christian Heimese6dac002018-08-30 07:25:49 +0200455 maxDiff = None
456
Antoine Pitrou480a1242010-04-28 21:37:09 +0000457 def test_parse_cert(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000458 # note that this uses an 'unofficial' function in _ssl.c,
459 # provided solely for this test, to exercise the certificate
460 # parsing code
Christian Heimesbd5c7d22018-01-20 15:16:30 +0100461 self.assertEqual(
462 ssl._ssl._test_decode_cert(CERTFILE),
463 CERTFILE_INFO
464 )
465 self.assertEqual(
466 ssl._ssl._test_decode_cert(SIGNED_CERTFILE),
467 SIGNED_CERTFILE_INFO
468 )
469
Antoine Pitroud8c347a2011-10-01 19:20:25 +0200470 # Issue #13034: the subjectAltName in some certificates
471 # (notably projects.developer.nokia.com:443) wasn't parsed
472 p = ssl._ssl._test_decode_cert(NOKIACERT)
473 if support.verbose:
474 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
475 self.assertEqual(p['subjectAltName'],
476 (('DNS', 'projects.developer.nokia.com'),
477 ('DNS', 'projects.forum.nokia.com'))
478 )
Christian Heimesbd3a7f92013-11-21 03:40:15 +0100479 # extra OCSP and AIA fields
480 self.assertEqual(p['OCSP'], ('http://ocsp.verisign.com',))
481 self.assertEqual(p['caIssuers'],
482 ('http://SVRIntl-G3-aia.verisign.com/SVRIntlG3.cer',))
483 self.assertEqual(p['crlDistributionPoints'],
484 ('http://SVRIntl-G3-crl.verisign.com/SVRIntlG3.crl',))
Thomas Woutersed03b412007-08-28 21:37:11 +0000485
Christian Heimesa37f5242019-01-15 23:47:42 +0100486 def test_parse_cert_CVE_2019_5010(self):
487 p = ssl._ssl._test_decode_cert(TALOS_INVALID_CRLDP)
488 if support.verbose:
489 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
490 self.assertEqual(
491 p,
492 {
493 'issuer': (
494 (('countryName', 'UK'),), (('commonName', 'cody-ca'),)),
495 'notAfter': 'Jun 14 18:00:58 2028 GMT',
496 'notBefore': 'Jun 18 18:00:58 2018 GMT',
497 'serialNumber': '02',
498 'subject': ((('countryName', 'UK'),),
499 (('commonName',
500 'codenomicon-vm-2.test.lal.cisco.com'),)),
501 'subjectAltName': (
502 ('DNS', 'codenomicon-vm-2.test.lal.cisco.com'),),
503 'version': 3
504 }
505 )
506
Christian Heimes824f7f32013-08-17 00:54:47 +0200507 def test_parse_cert_CVE_2013_4238(self):
508 p = ssl._ssl._test_decode_cert(NULLBYTECERT)
509 if support.verbose:
510 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
511 subject = ((('countryName', 'US'),),
512 (('stateOrProvinceName', 'Oregon'),),
513 (('localityName', 'Beaverton'),),
514 (('organizationName', 'Python Software Foundation'),),
515 (('organizationalUnitName', 'Python Core Development'),),
516 (('commonName', 'null.python.org\x00example.org'),),
517 (('emailAddress', 'python-dev@python.org'),))
518 self.assertEqual(p['subject'], subject)
519 self.assertEqual(p['issuer'], subject)
Christian Heimes157c9832013-08-25 14:12:41 +0200520 if ssl._OPENSSL_API_VERSION >= (0, 9, 8):
521 san = (('DNS', 'altnull.python.org\x00example.com'),
522 ('email', 'null@python.org\x00user@example.org'),
523 ('URI', 'http://null.python.org\x00http://example.org'),
524 ('IP Address', '192.0.2.1'),
Christian Heimes2b7de662019-12-07 17:59:36 +0100525 ('IP Address', '2001:DB8:0:0:0:0:0:1'))
Christian Heimes157c9832013-08-25 14:12:41 +0200526 else:
527 # OpenSSL 0.9.7 doesn't support IPv6 addresses in subjectAltName
528 san = (('DNS', 'altnull.python.org\x00example.com'),
529 ('email', 'null@python.org\x00user@example.org'),
530 ('URI', 'http://null.python.org\x00http://example.org'),
531 ('IP Address', '192.0.2.1'),
532 ('IP Address', '<invalid>'))
533
534 self.assertEqual(p['subjectAltName'], san)
Christian Heimes824f7f32013-08-17 00:54:47 +0200535
Christian Heimes1c03abd2016-09-06 23:25:35 +0200536 def test_parse_all_sans(self):
537 p = ssl._ssl._test_decode_cert(ALLSANFILE)
538 self.assertEqual(p['subjectAltName'],
539 (
540 ('DNS', 'allsans'),
541 ('othername', '<unsupported>'),
542 ('othername', '<unsupported>'),
543 ('email', 'user@example.org'),
544 ('DNS', 'www.example.org'),
545 ('DirName',
546 ((('countryName', 'XY'),),
547 (('localityName', 'Castle Anthrax'),),
548 (('organizationName', 'Python Software Foundation'),),
549 (('commonName', 'dirname example'),))),
550 ('URI', 'https://www.python.org/'),
551 ('IP Address', '127.0.0.1'),
Christian Heimes2b7de662019-12-07 17:59:36 +0100552 ('IP Address', '0:0:0:0:0:0:0:1'),
Christian Heimes1c03abd2016-09-06 23:25:35 +0200553 ('Registered ID', '1.2.3.4.5')
554 )
555 )
556
Antoine Pitrou480a1242010-04-28 21:37:09 +0000557 def test_DER_to_PEM(self):
Martin Panter3d81d932016-01-14 09:36:00 +0000558 with open(CAFILE_CACERT, 'r') as f:
Antoine Pitrou480a1242010-04-28 21:37:09 +0000559 pem = f.read()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000560 d1 = ssl.PEM_cert_to_DER_cert(pem)
561 p2 = ssl.DER_cert_to_PEM_cert(d1)
562 d2 = ssl.PEM_cert_to_DER_cert(p2)
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000563 self.assertEqual(d1, d2)
Antoine Pitrou9bfbe612010-04-27 22:08:08 +0000564 if not p2.startswith(ssl.PEM_HEADER + '\n'):
565 self.fail("DER-to-PEM didn't include correct header:\n%r\n" % p2)
566 if not p2.endswith('\n' + ssl.PEM_FOOTER + '\n'):
567 self.fail("DER-to-PEM didn't include correct footer:\n%r\n" % p2)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000568
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000569 def test_openssl_version(self):
570 n = ssl.OPENSSL_VERSION_NUMBER
571 t = ssl.OPENSSL_VERSION_INFO
572 s = ssl.OPENSSL_VERSION
573 self.assertIsInstance(n, int)
574 self.assertIsInstance(t, tuple)
575 self.assertIsInstance(s, str)
576 # Some sanity checks follow
577 # >= 0.9
578 self.assertGreaterEqual(n, 0x900000)
Christian Heimes2b7de662019-12-07 17:59:36 +0100579 # < 4.0
580 self.assertLess(n, 0x40000000)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000581 major, minor, fix, patch, status = t
Christian Heimes2b7de662019-12-07 17:59:36 +0100582 self.assertGreaterEqual(major, 1)
583 self.assertLess(major, 4)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000584 self.assertGreaterEqual(minor, 0)
585 self.assertLess(minor, 256)
586 self.assertGreaterEqual(fix, 0)
587 self.assertLess(fix, 256)
588 self.assertGreaterEqual(patch, 0)
Ned Deily05784a72015-02-05 17:20:13 +1100589 self.assertLessEqual(patch, 63)
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000590 self.assertGreaterEqual(status, 0)
591 self.assertLessEqual(status, 15)
Antoine Pitroudfab9352014-07-21 18:35:01 -0400592 # Version string as returned by {Open,Libre}SSL, the format might change
Christian Heimes598894f2016-09-05 23:19:05 +0200593 if IS_LIBRESSL:
594 self.assertTrue(s.startswith("LibreSSL {:d}".format(major)),
Victor Stinner789b8052015-01-06 11:51:06 +0100595 (s, t, hex(n)))
Antoine Pitroudfab9352014-07-21 18:35:01 -0400596 else:
597 self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)),
Victor Stinner789b8052015-01-06 11:51:06 +0100598 (s, t, hex(n)))
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000599
Antoine Pitrou9d543662010-04-23 23:10:32 +0000600 @support.cpython_only
601 def test_refcycle(self):
602 # Issue #7943: an SSL object doesn't create reference cycles with
603 # itself.
604 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200605 ss = test_wrap_socket(s)
Antoine Pitrou9d543662010-04-23 23:10:32 +0000606 wr = weakref.ref(ss)
Hai Shia7f5d932020-08-04 00:41:24 +0800607 with warnings_helper.check_warnings(("", ResourceWarning)):
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100608 del ss
Victor Stinnere0b75b72016-03-21 17:26:04 +0100609 self.assertEqual(wr(), None)
Antoine Pitrou9d543662010-04-23 23:10:32 +0000610
Antoine Pitroua468adc2010-09-14 14:43:44 +0000611 def test_wrapped_unconnected(self):
612 # Methods on an unconnected SSLSocket propagate the original
Andrew Svetlov0832af62012-12-18 23:10:48 +0200613 # OSError raise by the underlying socket object.
Antoine Pitroua468adc2010-09-14 14:43:44 +0000614 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200615 with test_wrap_socket(s) as ss:
Antoine Pitroue9bb4732013-01-12 21:56:56 +0100616 self.assertRaises(OSError, ss.recv, 1)
617 self.assertRaises(OSError, ss.recv_into, bytearray(b'x'))
618 self.assertRaises(OSError, ss.recvfrom, 1)
619 self.assertRaises(OSError, ss.recvfrom_into, bytearray(b'x'), 1)
620 self.assertRaises(OSError, ss.send, b'x')
621 self.assertRaises(OSError, ss.sendto, b'x', ('0.0.0.0', 0))
Serhiy Storchaka42b1d612018-12-06 22:36:55 +0200622 self.assertRaises(NotImplementedError, ss.dup)
Christian Heimes141c5e82018-02-24 21:10:57 +0100623 self.assertRaises(NotImplementedError, ss.sendmsg,
624 [b'x'], (), 0, ('0.0.0.0', 0))
Serhiy Storchaka42b1d612018-12-06 22:36:55 +0200625 self.assertRaises(NotImplementedError, ss.recvmsg, 100)
626 self.assertRaises(NotImplementedError, ss.recvmsg_into,
627 [bytearray(100)])
Antoine Pitroua468adc2010-09-14 14:43:44 +0000628
Antoine Pitrou40f08742010-04-24 22:04:40 +0000629 def test_timeout(self):
630 # Issue #8524: when creating an SSL socket, the timeout of the
631 # original socket should be retained.
632 for timeout in (None, 0.0, 5.0):
633 s = socket.socket(socket.AF_INET)
634 s.settimeout(timeout)
Christian Heimesd0486372016-09-10 23:23:33 +0200635 with test_wrap_socket(s) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100636 self.assertEqual(timeout, ss.gettimeout())
Antoine Pitrou40f08742010-04-24 22:04:40 +0000637
Christian Heimesd0486372016-09-10 23:23:33 +0200638 def test_errors_sslwrap(self):
Giampaolo Rodolà745ab382010-08-29 19:25:49 +0000639 sock = socket.socket()
Ezio Melottied3a7d22010-12-01 02:32:32 +0000640 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000641 "certfile must be specified",
642 ssl.wrap_socket, sock, keyfile=CERTFILE)
Ezio Melottied3a7d22010-12-01 02:32:32 +0000643 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000644 "certfile must be specified for server-side operations",
645 ssl.wrap_socket, sock, server_side=True)
Ezio Melottied3a7d22010-12-01 02:32:32 +0000646 self.assertRaisesRegex(ValueError,
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000647 "certfile must be specified for server-side operations",
Christian Heimesd0486372016-09-10 23:23:33 +0200648 ssl.wrap_socket, sock, server_side=True, certfile="")
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100649 with ssl.wrap_socket(sock, server_side=True, certfile=CERTFILE) as s:
650 self.assertRaisesRegex(ValueError, "can't connect in server-side mode",
Christian Heimesd0486372016-09-10 23:23:33 +0200651 s.connect, (HOST, 8080))
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200652 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000653 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000654 ssl.wrap_socket(sock, certfile=NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +0000655 self.assertEqual(cm.exception.errno, errno.ENOENT)
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,
659 certfile=CERTFILE, keyfile=NONEXISTINGCERT)
Giampaolo Rodolà8b7da622010-08-30 18:28:05 +0000660 self.assertEqual(cm.exception.errno, errno.ENOENT)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200661 with self.assertRaises(OSError) as cm:
Antoine Pitroud2eca372010-10-29 23:41:37 +0000662 with socket.socket() as sock:
Martin Panter407b62f2016-01-30 03:41:43 +0000663 ssl.wrap_socket(sock,
664 certfile=NONEXISTINGCERT, keyfile=NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +0000665 self.assertEqual(cm.exception.errno, errno.ENOENT)
Giampaolo Rodolà745ab382010-08-29 19:25:49 +0000666
Martin Panter3464ea22016-02-01 21:58:11 +0000667 def bad_cert_test(self, certfile):
668 """Check that trying to use the given client certificate fails"""
669 certfile = os.path.join(os.path.dirname(__file__) or os.curdir,
670 certfile)
671 sock = socket.socket()
672 self.addCleanup(sock.close)
673 with self.assertRaises(ssl.SSLError):
Christian Heimesd0486372016-09-10 23:23:33 +0200674 test_wrap_socket(sock,
Christian Heimesa170fa12017-09-15 20:27:30 +0200675 certfile=certfile)
Martin Panter3464ea22016-02-01 21:58:11 +0000676
677 def test_empty_cert(self):
678 """Wrapping with an empty cert file"""
679 self.bad_cert_test("nullcert.pem")
680
681 def test_malformed_cert(self):
682 """Wrapping with a badly formatted certificate (syntax error)"""
683 self.bad_cert_test("badcert.pem")
684
685 def test_malformed_key(self):
686 """Wrapping with a badly formatted key (syntax error)"""
687 self.bad_cert_test("badkey.pem")
688
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000689 def test_match_hostname(self):
690 def ok(cert, hostname):
691 ssl.match_hostname(cert, hostname)
692 def fail(cert, hostname):
693 self.assertRaises(ssl.CertificateError,
694 ssl.match_hostname, cert, hostname)
695
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100696 # -- Hostname matching --
697
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000698 cert = {'subject': ((('commonName', 'example.com'),),)}
699 ok(cert, 'example.com')
700 ok(cert, 'ExAmple.cOm')
701 fail(cert, 'www.example.com')
702 fail(cert, '.example.com')
703 fail(cert, 'example.org')
704 fail(cert, 'exampleXcom')
705
706 cert = {'subject': ((('commonName', '*.a.com'),),)}
707 ok(cert, 'foo.a.com')
708 fail(cert, 'bar.foo.a.com')
709 fail(cert, 'a.com')
710 fail(cert, 'Xa.com')
711 fail(cert, '.a.com')
712
Mandeep Singhede2ac92017-11-27 04:01:27 +0530713 # only match wildcards when they are the only thing
714 # in left-most segment
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000715 cert = {'subject': ((('commonName', 'f*.com'),),)}
Mandeep Singhede2ac92017-11-27 04:01:27 +0530716 fail(cert, 'foo.com')
717 fail(cert, 'f.com')
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000718 fail(cert, 'bar.com')
719 fail(cert, 'foo.a.com')
720 fail(cert, 'bar.foo.com')
721
Christian Heimes824f7f32013-08-17 00:54:47 +0200722 # NULL bytes are bad, CVE-2013-4073
723 cert = {'subject': ((('commonName',
724 'null.python.org\x00example.org'),),)}
725 ok(cert, 'null.python.org\x00example.org') # or raise an error?
726 fail(cert, 'example.org')
727 fail(cert, 'null.python.org')
728
Georg Brandl72c98d32013-10-27 07:16:53 +0100729 # error cases with wildcards
730 cert = {'subject': ((('commonName', '*.*.a.com'),),)}
731 fail(cert, 'bar.foo.a.com')
732 fail(cert, 'a.com')
733 fail(cert, 'Xa.com')
734 fail(cert, '.a.com')
735
736 cert = {'subject': ((('commonName', 'a.*.com'),),)}
737 fail(cert, 'a.foo.com')
738 fail(cert, 'a..com')
739 fail(cert, 'a.com')
740
741 # wildcard doesn't match IDNA prefix 'xn--'
742 idna = 'püthon.python.org'.encode("idna").decode("ascii")
743 cert = {'subject': ((('commonName', idna),),)}
744 ok(cert, idna)
745 cert = {'subject': ((('commonName', 'x*.python.org'),),)}
746 fail(cert, idna)
747 cert = {'subject': ((('commonName', 'xn--p*.python.org'),),)}
748 fail(cert, idna)
749
750 # wildcard in first fragment and IDNA A-labels in sequent fragments
751 # are supported.
752 idna = 'www*.pythön.org'.encode("idna").decode("ascii")
753 cert = {'subject': ((('commonName', idna),),)}
Mandeep Singhede2ac92017-11-27 04:01:27 +0530754 fail(cert, 'www.pythön.org'.encode("idna").decode("ascii"))
755 fail(cert, 'www1.pythön.org'.encode("idna").decode("ascii"))
Georg Brandl72c98d32013-10-27 07:16:53 +0100756 fail(cert, 'ftp.pythön.org'.encode("idna").decode("ascii"))
757 fail(cert, 'pythön.org'.encode("idna").decode("ascii"))
758
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000759 # Slightly fake real-world example
760 cert = {'notAfter': 'Jun 26 21:41:46 2011 GMT',
761 'subject': ((('commonName', 'linuxfrz.org'),),),
762 'subjectAltName': (('DNS', 'linuxfr.org'),
763 ('DNS', 'linuxfr.com'),
764 ('othername', '<unsupported>'))}
765 ok(cert, 'linuxfr.org')
766 ok(cert, 'linuxfr.com')
767 # Not a "DNS" entry
768 fail(cert, '<unsupported>')
769 # When there is a subjectAltName, commonName isn't used
770 fail(cert, 'linuxfrz.org')
771
772 # A pristine real-world example
773 cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT',
774 'subject': ((('countryName', 'US'),),
775 (('stateOrProvinceName', 'California'),),
776 (('localityName', 'Mountain View'),),
777 (('organizationName', 'Google Inc'),),
778 (('commonName', 'mail.google.com'),))}
779 ok(cert, 'mail.google.com')
780 fail(cert, 'gmail.com')
781 # Only commonName is considered
782 fail(cert, 'California')
783
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100784 # -- IPv4 matching --
785 cert = {'subject': ((('commonName', 'example.com'),),),
786 'subjectAltName': (('DNS', 'example.com'),
787 ('IP Address', '10.11.12.13'),
Christian Heimes477b1b22019-07-02 20:39:42 +0200788 ('IP Address', '14.15.16.17'),
789 ('IP Address', '127.0.0.1'))}
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100790 ok(cert, '10.11.12.13')
791 ok(cert, '14.15.16.17')
Christian Heimes477b1b22019-07-02 20:39:42 +0200792 # socket.inet_ntoa(socket.inet_aton('127.1')) == '127.0.0.1'
793 fail(cert, '127.1')
794 fail(cert, '14.15.16.17 ')
795 fail(cert, '14.15.16.17 extra data')
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100796 fail(cert, '14.15.16.18')
797 fail(cert, 'example.net')
798
799 # -- IPv6 matching --
Serhiy Storchaka16994912020-04-25 10:06:29 +0300800 if socket_helper.IPV6_ENABLED:
Christian Heimesaef12832018-02-24 14:35:56 +0100801 cert = {'subject': ((('commonName', 'example.com'),),),
802 'subjectAltName': (
803 ('DNS', 'example.com'),
804 ('IP Address', '2001:0:0:0:0:0:0:CAFE\n'),
805 ('IP Address', '2003:0:0:0:0:0:0:BABA\n'))}
806 ok(cert, '2001::cafe')
807 ok(cert, '2003::baba')
Christian Heimes477b1b22019-07-02 20:39:42 +0200808 fail(cert, '2003::baba ')
809 fail(cert, '2003::baba extra data')
Christian Heimesaef12832018-02-24 14:35:56 +0100810 fail(cert, '2003::bebe')
811 fail(cert, 'example.net')
Antoine Pitrouc481bfb2015-02-15 18:12:20 +0100812
813 # -- Miscellaneous --
814
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000815 # Neither commonName nor subjectAltName
816 cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT',
817 'subject': ((('countryName', 'US'),),
818 (('stateOrProvinceName', 'California'),),
819 (('localityName', 'Mountain View'),),
820 (('organizationName', 'Google Inc'),))}
821 fail(cert, 'mail.google.com')
822
Antoine Pitrou1c86b442011-05-06 15:19:49 +0200823 # No DNS entry in subjectAltName but a commonName
824 cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT',
825 'subject': ((('countryName', 'US'),),
826 (('stateOrProvinceName', 'California'),),
827 (('localityName', 'Mountain View'),),
828 (('commonName', 'mail.google.com'),)),
829 'subjectAltName': (('othername', 'blabla'), )}
830 ok(cert, 'mail.google.com')
831
832 # No DNS entry subjectAltName and no commonName
833 cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT',
834 'subject': ((('countryName', 'US'),),
835 (('stateOrProvinceName', 'California'),),
836 (('localityName', 'Mountain View'),),
837 (('organizationName', 'Google Inc'),)),
838 'subjectAltName': (('othername', 'blabla'),)}
839 fail(cert, 'google.com')
840
Antoine Pitrou59fdd672010-10-08 10:37:08 +0000841 # Empty cert / no cert
842 self.assertRaises(ValueError, ssl.match_hostname, None, 'example.com')
843 self.assertRaises(ValueError, ssl.match_hostname, {}, 'example.com')
844
Antoine Pitrou636f93c2013-05-18 17:56:42 +0200845 # Issue #17980: avoid denials of service by refusing more than one
846 # wildcard per fragment.
Christian Heimesaef12832018-02-24 14:35:56 +0100847 cert = {'subject': ((('commonName', 'a*b.example.com'),),)}
848 with self.assertRaisesRegex(
849 ssl.CertificateError,
850 "partial wildcards in leftmost label are not supported"):
851 ssl.match_hostname(cert, 'axxb.example.com')
852
853 cert = {'subject': ((('commonName', 'www.*.example.com'),),)}
854 with self.assertRaisesRegex(
855 ssl.CertificateError,
856 "wildcard can only be present in the leftmost label"):
857 ssl.match_hostname(cert, 'www.sub.example.com')
858
859 cert = {'subject': ((('commonName', 'a*b*.example.com'),),)}
860 with self.assertRaisesRegex(
861 ssl.CertificateError,
862 "too many wildcards"):
863 ssl.match_hostname(cert, 'axxbxxc.example.com')
864
865 cert = {'subject': ((('commonName', '*'),),)}
866 with self.assertRaisesRegex(
867 ssl.CertificateError,
868 "sole wildcard without additional labels are not support"):
869 ssl.match_hostname(cert, 'host')
870
871 cert = {'subject': ((('commonName', '*.com'),),)}
872 with self.assertRaisesRegex(
873 ssl.CertificateError,
874 r"hostname 'com' doesn't match '\*.com'"):
875 ssl.match_hostname(cert, 'com')
876
877 # extra checks for _inet_paton()
878 for invalid in ['1', '', '1.2.3', '256.0.0.1', '127.0.0.1/24']:
879 with self.assertRaises(ValueError):
880 ssl._inet_paton(invalid)
881 for ipaddr in ['127.0.0.1', '192.168.0.1']:
882 self.assertTrue(ssl._inet_paton(ipaddr))
Serhiy Storchaka16994912020-04-25 10:06:29 +0300883 if socket_helper.IPV6_ENABLED:
Christian Heimesaef12832018-02-24 14:35:56 +0100884 for ipaddr in ['::1', '2001:db8:85a3::8a2e:370:7334']:
885 self.assertTrue(ssl._inet_paton(ipaddr))
Antoine Pitrou636f93c2013-05-18 17:56:42 +0200886
Antoine Pitroud5323212010-10-22 18:19:07 +0000887 def test_server_side(self):
888 # server_hostname doesn't work for server sockets
Christian Heimesa170fa12017-09-15 20:27:30 +0200889 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroud2eca372010-10-29 23:41:37 +0000890 with socket.socket() as sock:
891 self.assertRaises(ValueError, ctx.wrap_socket, sock, True,
892 server_hostname="some.hostname")
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000893
Antoine Pitroud6494802011-07-21 01:11:30 +0200894 def test_unknown_channel_binding(self):
895 # should raise ValueError for unknown type
Giampaolo Rodolaeb7e29f2019-04-09 00:34:02 +0200896 s = socket.create_server(('127.0.0.1', 0))
Antoine Pitroub1fdf472014-10-05 20:41:53 +0200897 c = socket.socket(socket.AF_INET)
898 c.connect(s.getsockname())
Christian Heimesd0486372016-09-10 23:23:33 +0200899 with test_wrap_socket(c, do_handshake_on_connect=False) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100900 with self.assertRaises(ValueError):
901 ss.get_channel_binding("unknown-type")
Antoine Pitroub1fdf472014-10-05 20:41:53 +0200902 s.close()
Antoine Pitroud6494802011-07-21 01:11:30 +0200903
904 @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES,
905 "'tls-unique' channel binding not available")
906 def test_tls_unique_channel_binding(self):
907 # unconnected should return None for known type
908 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200909 with test_wrap_socket(s) as ss:
Antoine Pitroue1ceb502013-01-12 21:54:44 +0100910 self.assertIsNone(ss.get_channel_binding("tls-unique"))
Antoine Pitroud6494802011-07-21 01:11:30 +0200911 # the same for server-side
912 s = socket.socket(socket.AF_INET)
Christian Heimesd0486372016-09-10 23:23:33 +0200913 with test_wrap_socket(s, server_side=True, certfile=CERTFILE) 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
Benjamin Peterson36f7b972013-01-10 14:16:20 -0600916 def test_dealloc_warn(self):
Christian Heimesd0486372016-09-10 23:23:33 +0200917 ss = test_wrap_socket(socket.socket(socket.AF_INET))
Benjamin Peterson36f7b972013-01-10 14:16:20 -0600918 r = repr(ss)
919 with self.assertWarns(ResourceWarning) as cm:
920 ss = None
921 support.gc_collect()
922 self.assertIn(r, str(cm.warning.args[0]))
923
Christian Heimes6d7ad132013-06-09 18:02:55 +0200924 def test_get_default_verify_paths(self):
925 paths = ssl.get_default_verify_paths()
926 self.assertEqual(len(paths), 6)
927 self.assertIsInstance(paths, ssl.DefaultVerifyPaths)
928
Hai Shia7f5d932020-08-04 00:41:24 +0800929 with os_helper.EnvironmentVarGuard() as env:
Christian Heimes6d7ad132013-06-09 18:02:55 +0200930 env["SSL_CERT_DIR"] = CAPATH
931 env["SSL_CERT_FILE"] = CERTFILE
932 paths = ssl.get_default_verify_paths()
933 self.assertEqual(paths.cafile, CERTFILE)
934 self.assertEqual(paths.capath, CAPATH)
935
Christian Heimes44109d72013-11-22 01:51:30 +0100936 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
937 def test_enum_certificates(self):
938 self.assertTrue(ssl.enum_certificates("CA"))
939 self.assertTrue(ssl.enum_certificates("ROOT"))
940
941 self.assertRaises(TypeError, ssl.enum_certificates)
942 self.assertRaises(WindowsError, ssl.enum_certificates, "")
943
Christian Heimesc2d65e12013-11-22 16:13:55 +0100944 trust_oids = set()
945 for storename in ("CA", "ROOT"):
946 store = ssl.enum_certificates(storename)
947 self.assertIsInstance(store, list)
948 for element in store:
949 self.assertIsInstance(element, tuple)
950 self.assertEqual(len(element), 3)
951 cert, enc, trust = element
952 self.assertIsInstance(cert, bytes)
953 self.assertIn(enc, {"x509_asn", "pkcs_7_asn"})
Christian Heimes915cd3f2019-09-09 18:06:55 +0200954 self.assertIsInstance(trust, (frozenset, set, bool))
955 if isinstance(trust, (frozenset, set)):
Christian Heimesc2d65e12013-11-22 16:13:55 +0100956 trust_oids.update(trust)
Christian Heimes44109d72013-11-22 01:51:30 +0100957
958 serverAuth = "1.3.6.1.5.5.7.3.1"
Christian Heimesc2d65e12013-11-22 16:13:55 +0100959 self.assertIn(serverAuth, trust_oids)
Christian Heimes6d7ad132013-06-09 18:02:55 +0200960
Christian Heimes46bebee2013-06-09 19:03:31 +0200961 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
Christian Heimes44109d72013-11-22 01:51:30 +0100962 def test_enum_crls(self):
963 self.assertTrue(ssl.enum_crls("CA"))
964 self.assertRaises(TypeError, ssl.enum_crls)
965 self.assertRaises(WindowsError, ssl.enum_crls, "")
Christian Heimes46bebee2013-06-09 19:03:31 +0200966
Christian Heimes44109d72013-11-22 01:51:30 +0100967 crls = ssl.enum_crls("CA")
968 self.assertIsInstance(crls, list)
969 for element in crls:
970 self.assertIsInstance(element, tuple)
971 self.assertEqual(len(element), 2)
972 self.assertIsInstance(element[0], bytes)
973 self.assertIn(element[1], {"x509_asn", "pkcs_7_asn"})
Christian Heimes46bebee2013-06-09 19:03:31 +0200974
Christian Heimes46bebee2013-06-09 19:03:31 +0200975
Christian Heimesa6bc95a2013-11-17 19:59:14 +0100976 def test_asn1object(self):
977 expected = (129, 'serverAuth', 'TLS Web Server Authentication',
978 '1.3.6.1.5.5.7.3.1')
979
980 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1')
981 self.assertEqual(val, expected)
982 self.assertEqual(val.nid, 129)
983 self.assertEqual(val.shortname, 'serverAuth')
984 self.assertEqual(val.longname, 'TLS Web Server Authentication')
985 self.assertEqual(val.oid, '1.3.6.1.5.5.7.3.1')
986 self.assertIsInstance(val, ssl._ASN1Object)
987 self.assertRaises(ValueError, ssl._ASN1Object, 'serverAuth')
988
989 val = ssl._ASN1Object.fromnid(129)
990 self.assertEqual(val, expected)
991 self.assertIsInstance(val, ssl._ASN1Object)
992 self.assertRaises(ValueError, ssl._ASN1Object.fromnid, -1)
Christian Heimes5398e1a2013-11-22 16:20:53 +0100993 with self.assertRaisesRegex(ValueError, "unknown NID 100000"):
994 ssl._ASN1Object.fromnid(100000)
Christian Heimesa6bc95a2013-11-17 19:59:14 +0100995 for i in range(1000):
996 try:
997 obj = ssl._ASN1Object.fromnid(i)
998 except ValueError:
999 pass
1000 else:
1001 self.assertIsInstance(obj.nid, int)
1002 self.assertIsInstance(obj.shortname, str)
1003 self.assertIsInstance(obj.longname, str)
1004 self.assertIsInstance(obj.oid, (str, type(None)))
1005
1006 val = ssl._ASN1Object.fromname('TLS Web Server Authentication')
1007 self.assertEqual(val, expected)
1008 self.assertIsInstance(val, ssl._ASN1Object)
1009 self.assertEqual(ssl._ASN1Object.fromname('serverAuth'), expected)
1010 self.assertEqual(ssl._ASN1Object.fromname('1.3.6.1.5.5.7.3.1'),
1011 expected)
Christian Heimes5398e1a2013-11-22 16:20:53 +01001012 with self.assertRaisesRegex(ValueError, "unknown object 'serverauth'"):
1013 ssl._ASN1Object.fromname('serverauth')
Christian Heimesa6bc95a2013-11-17 19:59:14 +01001014
Christian Heimes72d28502013-11-23 13:56:58 +01001015 def test_purpose_enum(self):
1016 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1')
1017 self.assertIsInstance(ssl.Purpose.SERVER_AUTH, ssl._ASN1Object)
1018 self.assertEqual(ssl.Purpose.SERVER_AUTH, val)
1019 self.assertEqual(ssl.Purpose.SERVER_AUTH.nid, 129)
1020 self.assertEqual(ssl.Purpose.SERVER_AUTH.shortname, 'serverAuth')
1021 self.assertEqual(ssl.Purpose.SERVER_AUTH.oid,
1022 '1.3.6.1.5.5.7.3.1')
1023
1024 val = ssl._ASN1Object('1.3.6.1.5.5.7.3.2')
1025 self.assertIsInstance(ssl.Purpose.CLIENT_AUTH, ssl._ASN1Object)
1026 self.assertEqual(ssl.Purpose.CLIENT_AUTH, val)
1027 self.assertEqual(ssl.Purpose.CLIENT_AUTH.nid, 130)
1028 self.assertEqual(ssl.Purpose.CLIENT_AUTH.shortname, 'clientAuth')
1029 self.assertEqual(ssl.Purpose.CLIENT_AUTH.oid,
1030 '1.3.6.1.5.5.7.3.2')
1031
Antoine Pitrou3e86ba42013-12-28 17:26:33 +01001032 def test_unsupported_dtls(self):
1033 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
1034 self.addCleanup(s.close)
1035 with self.assertRaises(NotImplementedError) as cx:
Christian Heimesd0486372016-09-10 23:23:33 +02001036 test_wrap_socket(s, cert_reqs=ssl.CERT_NONE)
Antoine Pitrou3e86ba42013-12-28 17:26:33 +01001037 self.assertEqual(str(cx.exception), "only stream sockets are supported")
Christian Heimesa170fa12017-09-15 20:27:30 +02001038 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou3e86ba42013-12-28 17:26:33 +01001039 with self.assertRaises(NotImplementedError) as cx:
1040 ctx.wrap_socket(s)
1041 self.assertEqual(str(cx.exception), "only stream sockets are supported")
1042
Antoine Pitrouc695c952014-04-28 20:57:36 +02001043 def cert_time_ok(self, timestring, timestamp):
1044 self.assertEqual(ssl.cert_time_to_seconds(timestring), timestamp)
1045
1046 def cert_time_fail(self, timestring):
1047 with self.assertRaises(ValueError):
1048 ssl.cert_time_to_seconds(timestring)
1049
1050 @unittest.skipUnless(utc_offset(),
1051 'local time needs to be different from UTC')
1052 def test_cert_time_to_seconds_timezone(self):
1053 # Issue #19940: ssl.cert_time_to_seconds() returns wrong
1054 # results if local timezone is not UTC
1055 self.cert_time_ok("May 9 00:00:00 2007 GMT", 1178668800.0)
1056 self.cert_time_ok("Jan 5 09:34:43 2018 GMT", 1515144883.0)
1057
1058 def test_cert_time_to_seconds(self):
1059 timestring = "Jan 5 09:34:43 2018 GMT"
1060 ts = 1515144883.0
1061 self.cert_time_ok(timestring, ts)
1062 # accept keyword parameter, assert its name
1063 self.assertEqual(ssl.cert_time_to_seconds(cert_time=timestring), ts)
1064 # accept both %e and %d (space or zero generated by strftime)
1065 self.cert_time_ok("Jan 05 09:34:43 2018 GMT", ts)
1066 # case-insensitive
1067 self.cert_time_ok("JaN 5 09:34:43 2018 GmT", ts)
1068 self.cert_time_fail("Jan 5 09:34 2018 GMT") # no seconds
1069 self.cert_time_fail("Jan 5 09:34:43 2018") # no GMT
1070 self.cert_time_fail("Jan 5 09:34:43 2018 UTC") # not GMT timezone
1071 self.cert_time_fail("Jan 35 09:34:43 2018 GMT") # invalid day
1072 self.cert_time_fail("Jon 5 09:34:43 2018 GMT") # invalid month
1073 self.cert_time_fail("Jan 5 24:00:00 2018 GMT") # invalid hour
1074 self.cert_time_fail("Jan 5 09:60:43 2018 GMT") # invalid minute
1075
1076 newyear_ts = 1230768000.0
1077 # leap seconds
1078 self.cert_time_ok("Dec 31 23:59:60 2008 GMT", newyear_ts)
1079 # same timestamp
1080 self.cert_time_ok("Jan 1 00:00:00 2009 GMT", newyear_ts)
1081
1082 self.cert_time_ok("Jan 5 09:34:59 2018 GMT", 1515144899)
1083 # allow 60th second (even if it is not a leap second)
1084 self.cert_time_ok("Jan 5 09:34:60 2018 GMT", 1515144900)
1085 # allow 2nd leap second for compatibility with time.strptime()
1086 self.cert_time_ok("Jan 5 09:34:61 2018 GMT", 1515144901)
1087 self.cert_time_fail("Jan 5 09:34:62 2018 GMT") # invalid seconds
1088
Mike53f7a7c2017-12-14 14:04:53 +03001089 # no special treatment for the special value:
Antoine Pitrouc695c952014-04-28 20:57:36 +02001090 # 99991231235959Z (rfc 5280)
1091 self.cert_time_ok("Dec 31 23:59:59 9999 GMT", 253402300799.0)
1092
1093 @support.run_with_locale('LC_ALL', '')
1094 def test_cert_time_to_seconds_locale(self):
1095 # `cert_time_to_seconds()` should be locale independent
1096
1097 def local_february_name():
1098 return time.strftime('%b', (1, 2, 3, 4, 5, 6, 0, 0, 0))
1099
1100 if local_february_name().lower() == 'feb':
1101 self.skipTest("locale-specific month name needs to be "
1102 "different from C locale")
1103
1104 # locale-independent
1105 self.cert_time_ok("Feb 9 00:00:00 2007 GMT", 1170979200.0)
1106 self.cert_time_fail(local_february_name() + " 9 00:00:00 2007 GMT")
1107
Martin Panter3840b2a2016-03-27 01:53:46 +00001108 def test_connect_ex_error(self):
1109 server = socket.socket(socket.AF_INET)
1110 self.addCleanup(server.close)
Serhiy Storchaka16994912020-04-25 10:06:29 +03001111 port = socket_helper.bind_port(server) # Reserve port but don't listen
Christian Heimesd0486372016-09-10 23:23:33 +02001112 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001113 cert_reqs=ssl.CERT_REQUIRED)
1114 self.addCleanup(s.close)
1115 rc = s.connect_ex((HOST, port))
1116 # Issue #19919: Windows machines or VMs hosted on Windows
1117 # machines sometimes return EWOULDBLOCK.
1118 errors = (
1119 errno.ECONNREFUSED, errno.EHOSTUNREACH, errno.ETIMEDOUT,
1120 errno.EWOULDBLOCK,
1121 )
1122 self.assertIn(rc, errors)
1123
Christian Heimesa6bc95a2013-11-17 19:59:14 +01001124
Antoine Pitrou152efa22010-05-16 18:19:27 +00001125class ContextTests(unittest.TestCase):
1126
1127 def test_constructor(self):
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01001128 for protocol in PROTOCOLS:
1129 ssl.SSLContext(protocol)
Christian Heimes598894f2016-09-05 23:19:05 +02001130 ctx = ssl.SSLContext()
1131 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001132 self.assertRaises(ValueError, ssl.SSLContext, -1)
1133 self.assertRaises(ValueError, ssl.SSLContext, 42)
1134
1135 def test_protocol(self):
1136 for proto in PROTOCOLS:
1137 ctx = ssl.SSLContext(proto)
1138 self.assertEqual(ctx.protocol, proto)
1139
1140 def test_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001141 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001142 ctx.set_ciphers("ALL")
1143 ctx.set_ciphers("DEFAULT")
Ezio Melottied3a7d22010-12-01 02:32:32 +00001144 with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
Antoine Pitrou30474062010-05-16 23:46:26 +00001145 ctx.set_ciphers("^$:,;?*'dorothyx")
Antoine Pitrou152efa22010-05-16 18:19:27 +00001146
Christian Heimes892d66e2018-01-29 14:10:18 +01001147 @unittest.skipUnless(PY_SSL_DEFAULT_CIPHERS == 1,
1148 "Test applies only to Python default ciphers")
1149 def test_python_ciphers(self):
1150 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1151 ciphers = ctx.get_ciphers()
1152 for suite in ciphers:
1153 name = suite['name']
1154 self.assertNotIn("PSK", name)
1155 self.assertNotIn("SRP", name)
1156 self.assertNotIn("MD5", name)
1157 self.assertNotIn("RC4", name)
1158 self.assertNotIn("3DES", name)
1159
Christian Heimes25bfcd52016-09-06 00:04:45 +02001160 @unittest.skipIf(ssl.OPENSSL_VERSION_INFO < (1, 0, 2, 0, 0), 'OpenSSL too old')
1161 def test_get_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001162 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesea9b2dc2016-09-06 10:45:44 +02001163 ctx.set_ciphers('AESGCM')
Christian Heimes25bfcd52016-09-06 00:04:45 +02001164 names = set(d['name'] for d in ctx.get_ciphers())
Christian Heimes582282b2016-09-06 11:27:25 +02001165 self.assertIn('AES256-GCM-SHA384', names)
1166 self.assertIn('AES128-GCM-SHA256', names)
Christian Heimes25bfcd52016-09-06 00:04:45 +02001167
Antoine Pitroub5218772010-05-21 09:56:06 +00001168 def test_options(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001169 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Benjamin Petersona9dcdab2015-11-11 22:38:41 -08001170 # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value
Christian Heimes598894f2016-09-05 23:19:05 +02001171 default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
Christian Heimes358cfd42016-09-10 22:43:48 +02001172 # SSLContext also enables these by default
1173 default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE |
Christian Heimes05d9fe32018-02-27 08:55:39 +01001174 OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE |
Christian Heimes6f37ebc2021-04-09 17:59:21 +02001175 OP_ENABLE_MIDDLEBOX_COMPAT |
1176 OP_IGNORE_UNEXPECTED_EOF)
Christian Heimes598894f2016-09-05 23:19:05 +02001177 self.assertEqual(default, ctx.options)
Benjamin Petersona9dcdab2015-11-11 22:38:41 -08001178 ctx.options |= ssl.OP_NO_TLSv1
Christian Heimes598894f2016-09-05 23:19:05 +02001179 self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options)
Antoine Pitroub5218772010-05-21 09:56:06 +00001180 if can_clear_options():
Christian Heimes598894f2016-09-05 23:19:05 +02001181 ctx.options = (ctx.options & ~ssl.OP_NO_TLSv1)
1182 self.assertEqual(default, ctx.options)
Antoine Pitroub5218772010-05-21 09:56:06 +00001183 ctx.options = 0
Matthias Klosef7c56242016-06-12 23:40:00 -07001184 # Ubuntu has OP_NO_SSLv3 forced on by default
1185 self.assertEqual(0, ctx.options & ~ssl.OP_NO_SSLv3)
Antoine Pitroub5218772010-05-21 09:56:06 +00001186 else:
1187 with self.assertRaises(ValueError):
1188 ctx.options = 0
1189
Christian Heimesa170fa12017-09-15 20:27:30 +02001190 def test_verify_mode_protocol(self):
1191 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001192 # Default value
1193 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1194 ctx.verify_mode = ssl.CERT_OPTIONAL
1195 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1196 ctx.verify_mode = ssl.CERT_REQUIRED
1197 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1198 ctx.verify_mode = ssl.CERT_NONE
1199 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1200 with self.assertRaises(TypeError):
1201 ctx.verify_mode = None
1202 with self.assertRaises(ValueError):
1203 ctx.verify_mode = 42
1204
Christian Heimesa170fa12017-09-15 20:27:30 +02001205 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1206 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1207 self.assertFalse(ctx.check_hostname)
1208
1209 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1210 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1211 self.assertTrue(ctx.check_hostname)
1212
Christian Heimes61d478c2018-01-27 15:51:38 +01001213 def test_hostname_checks_common_name(self):
1214 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1215 self.assertTrue(ctx.hostname_checks_common_name)
1216 if ssl.HAS_NEVER_CHECK_COMMON_NAME:
1217 ctx.hostname_checks_common_name = True
1218 self.assertTrue(ctx.hostname_checks_common_name)
1219 ctx.hostname_checks_common_name = False
1220 self.assertFalse(ctx.hostname_checks_common_name)
1221 ctx.hostname_checks_common_name = True
1222 self.assertTrue(ctx.hostname_checks_common_name)
1223 else:
1224 with self.assertRaises(AttributeError):
1225 ctx.hostname_checks_common_name = True
Christian Heimesa170fa12017-09-15 20:27:30 +02001226
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001227 @requires_minimum_version
Christian Heimesc9bc49c2019-09-11 19:24:47 +02001228 @unittest.skipIf(IS_LIBRESSL, "see bpo-34001")
Christian Heimes698dde12018-02-27 11:54:43 +01001229 def test_min_max_version(self):
1230 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimes34de2d32019-01-18 16:09:30 +01001231 # OpenSSL default is MINIMUM_SUPPORTED, however some vendors like
1232 # Fedora override the setting to TLS 1.0.
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001233 minimum_range = {
1234 # stock OpenSSL
1235 ssl.TLSVersion.MINIMUM_SUPPORTED,
1236 # Fedora 29 uses TLS 1.0 by default
1237 ssl.TLSVersion.TLSv1,
1238 # RHEL 8 uses TLS 1.2 by default
1239 ssl.TLSVersion.TLSv1_2
1240 }
torsava34864d12019-12-02 17:15:42 +01001241 maximum_range = {
1242 # stock OpenSSL
1243 ssl.TLSVersion.MAXIMUM_SUPPORTED,
1244 # Fedora 32 uses TLS 1.3 by default
1245 ssl.TLSVersion.TLSv1_3
1246 }
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001247
Christian Heimes34de2d32019-01-18 16:09:30 +01001248 self.assertIn(
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001249 ctx.minimum_version, minimum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001250 )
torsava34864d12019-12-02 17:15:42 +01001251 self.assertIn(
1252 ctx.maximum_version, maximum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001253 )
1254
1255 ctx.minimum_version = ssl.TLSVersion.TLSv1_1
1256 ctx.maximum_version = ssl.TLSVersion.TLSv1_2
1257 self.assertEqual(
1258 ctx.minimum_version, ssl.TLSVersion.TLSv1_1
1259 )
1260 self.assertEqual(
1261 ctx.maximum_version, ssl.TLSVersion.TLSv1_2
1262 )
1263
1264 ctx.minimum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1265 ctx.maximum_version = ssl.TLSVersion.TLSv1
1266 self.assertEqual(
1267 ctx.minimum_version, ssl.TLSVersion.MINIMUM_SUPPORTED
1268 )
1269 self.assertEqual(
1270 ctx.maximum_version, ssl.TLSVersion.TLSv1
1271 )
1272
1273 ctx.maximum_version = ssl.TLSVersion.MAXIMUM_SUPPORTED
1274 self.assertEqual(
1275 ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED
1276 )
1277
1278 ctx.maximum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1279 self.assertIn(
1280 ctx.maximum_version,
1281 {ssl.TLSVersion.TLSv1, ssl.TLSVersion.SSLv3}
1282 )
1283
1284 ctx.minimum_version = ssl.TLSVersion.MAXIMUM_SUPPORTED
1285 self.assertIn(
1286 ctx.minimum_version,
1287 {ssl.TLSVersion.TLSv1_2, ssl.TLSVersion.TLSv1_3}
1288 )
1289
1290 with self.assertRaises(ValueError):
1291 ctx.minimum_version = 42
1292
1293 ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_1)
1294
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02001295 self.assertIn(
1296 ctx.minimum_version, minimum_range
Christian Heimes698dde12018-02-27 11:54:43 +01001297 )
1298 self.assertEqual(
1299 ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED
1300 )
1301 with self.assertRaises(ValueError):
1302 ctx.minimum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
1303 with self.assertRaises(ValueError):
1304 ctx.maximum_version = ssl.TLSVersion.TLSv1
1305
1306
matthewhughes9348e836bb2020-07-17 09:59:15 +01001307 @unittest.skipUnless(
1308 hasattr(ssl.SSLContext, 'security_level'),
1309 "requires OpenSSL >= 1.1.0"
1310 )
1311 def test_security_level(self):
1312 ctx = ssl.SSLContext()
1313 # The default security callback allows for levels between 0-5
1314 # with OpenSSL defaulting to 1, however some vendors override the
1315 # default value (e.g. Debian defaults to 2)
1316 security_level_range = {
1317 0,
1318 1, # OpenSSL default
1319 2, # Debian
1320 3,
1321 4,
1322 5,
1323 }
1324 self.assertIn(ctx.security_level, security_level_range)
1325
Christian Heimes2427b502013-11-23 11:24:32 +01001326 @unittest.skipUnless(have_verify_flags(),
1327 "verify_flags need OpenSSL > 0.9.8")
Christian Heimes22587792013-11-21 23:56:13 +01001328 def test_verify_flags(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001329 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Benjamin Peterson990fcaa2015-03-04 22:49:41 -05001330 # default value
1331 tf = getattr(ssl, "VERIFY_X509_TRUSTED_FIRST", 0)
1332 self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT | tf)
Christian Heimes22587792013-11-21 23:56:13 +01001333 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF
1334 self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_LEAF)
1335 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_CHAIN
1336 self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_CHAIN)
1337 ctx.verify_flags = ssl.VERIFY_DEFAULT
1338 self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT)
Chris Burre0b4aa02021-03-18 09:24:01 +01001339 ctx.verify_flags = ssl.VERIFY_ALLOW_PROXY_CERTS
1340 self.assertEqual(ctx.verify_flags, ssl.VERIFY_ALLOW_PROXY_CERTS)
Christian Heimes22587792013-11-21 23:56:13 +01001341 # supports any value
1342 ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT
1343 self.assertEqual(ctx.verify_flags,
1344 ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT)
1345 with self.assertRaises(TypeError):
1346 ctx.verify_flags = None
1347
Antoine Pitrou152efa22010-05-16 18:19:27 +00001348 def test_load_cert_chain(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001349 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001350 # Combined key and cert in a single file
Benjamin Peterson1ea070e2014-11-03 21:05:01 -05001351 ctx.load_cert_chain(CERTFILE, keyfile=None)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001352 ctx.load_cert_chain(CERTFILE, keyfile=CERTFILE)
1353 self.assertRaises(TypeError, ctx.load_cert_chain, keyfile=CERTFILE)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001354 with self.assertRaises(OSError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001355 ctx.load_cert_chain(NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +00001356 self.assertEqual(cm.exception.errno, errno.ENOENT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001357 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001358 ctx.load_cert_chain(BADCERT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001359 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001360 ctx.load_cert_chain(EMPTYCERT)
1361 # Separate key and cert
Christian Heimesa170fa12017-09-15 20:27:30 +02001362 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001363 ctx.load_cert_chain(ONLYCERT, ONLYKEY)
1364 ctx.load_cert_chain(certfile=ONLYCERT, keyfile=ONLYKEY)
1365 ctx.load_cert_chain(certfile=BYTES_ONLYCERT, keyfile=BYTES_ONLYKEY)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001366 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001367 ctx.load_cert_chain(ONLYCERT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001368 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001369 ctx.load_cert_chain(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(certfile=ONLYKEY, keyfile=ONLYCERT)
1372 # Mismatching key and cert
Christian Heimesa170fa12017-09-15 20:27:30 +02001373 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001374 with self.assertRaisesRegex(ssl.SSLError, "key values mismatch"):
Martin Panter3d81d932016-01-14 09:36:00 +00001375 ctx.load_cert_chain(CAFILE_CACERT, ONLYKEY)
Antoine Pitrou4fd1e6a2011-08-25 14:39:44 +02001376 # Password protected key and cert
1377 ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD)
1378 ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD.encode())
1379 ctx.load_cert_chain(CERTFILE_PROTECTED,
1380 password=bytearray(KEY_PASSWORD.encode()))
1381 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD)
1382 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD.encode())
1383 ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED,
1384 bytearray(KEY_PASSWORD.encode()))
1385 with self.assertRaisesRegex(TypeError, "should be a string"):
1386 ctx.load_cert_chain(CERTFILE_PROTECTED, password=True)
1387 with self.assertRaises(ssl.SSLError):
1388 ctx.load_cert_chain(CERTFILE_PROTECTED, password="badpass")
1389 with self.assertRaisesRegex(ValueError, "cannot be longer"):
1390 # openssl has a fixed limit on the password buffer.
1391 # PEM_BUFSIZE is generally set to 1kb.
1392 # Return a string larger than this.
1393 ctx.load_cert_chain(CERTFILE_PROTECTED, password=b'a' * 102400)
1394 # Password callback
1395 def getpass_unicode():
1396 return KEY_PASSWORD
1397 def getpass_bytes():
1398 return KEY_PASSWORD.encode()
1399 def getpass_bytearray():
1400 return bytearray(KEY_PASSWORD.encode())
1401 def getpass_badpass():
1402 return "badpass"
1403 def getpass_huge():
1404 return b'a' * (1024 * 1024)
1405 def getpass_bad_type():
1406 return 9
1407 def getpass_exception():
1408 raise Exception('getpass error')
1409 class GetPassCallable:
1410 def __call__(self):
1411 return KEY_PASSWORD
1412 def getpass(self):
1413 return KEY_PASSWORD
1414 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_unicode)
1415 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytes)
1416 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytearray)
1417 ctx.load_cert_chain(CERTFILE_PROTECTED, password=GetPassCallable())
1418 ctx.load_cert_chain(CERTFILE_PROTECTED,
1419 password=GetPassCallable().getpass)
1420 with self.assertRaises(ssl.SSLError):
1421 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_badpass)
1422 with self.assertRaisesRegex(ValueError, "cannot be longer"):
1423 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_huge)
1424 with self.assertRaisesRegex(TypeError, "must return a string"):
1425 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bad_type)
1426 with self.assertRaisesRegex(Exception, "getpass error"):
1427 ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_exception)
1428 # Make sure the password function isn't called if it isn't needed
1429 ctx.load_cert_chain(CERTFILE, password=getpass_exception)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001430
1431 def test_load_verify_locations(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001432 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou152efa22010-05-16 18:19:27 +00001433 ctx.load_verify_locations(CERTFILE)
1434 ctx.load_verify_locations(cafile=CERTFILE, capath=None)
1435 ctx.load_verify_locations(BYTES_CERTFILE)
1436 ctx.load_verify_locations(cafile=BYTES_CERTFILE, capath=None)
1437 self.assertRaises(TypeError, ctx.load_verify_locations)
Christian Heimesefff7062013-11-21 03:35:02 +01001438 self.assertRaises(TypeError, ctx.load_verify_locations, None, None, None)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001439 with self.assertRaises(OSError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001440 ctx.load_verify_locations(NONEXISTINGCERT)
Giampaolo Rodolà4a656eb2010-08-29 22:50:39 +00001441 self.assertEqual(cm.exception.errno, errno.ENOENT)
Ezio Melottied3a7d22010-12-01 02:32:32 +00001442 with self.assertRaisesRegex(ssl.SSLError, "PEM lib"):
Antoine Pitrou152efa22010-05-16 18:19:27 +00001443 ctx.load_verify_locations(BADCERT)
1444 ctx.load_verify_locations(CERTFILE, CAPATH)
1445 ctx.load_verify_locations(CERTFILE, capath=BYTES_CAPATH)
1446
Victor Stinner80f75e62011-01-29 11:31:20 +00001447 # Issue #10989: crash if the second argument type is invalid
1448 self.assertRaises(TypeError, ctx.load_verify_locations, None, True)
1449
Christian Heimesefff7062013-11-21 03:35:02 +01001450 def test_load_verify_cadata(self):
1451 # test cadata
1452 with open(CAFILE_CACERT) as f:
1453 cacert_pem = f.read()
1454 cacert_der = ssl.PEM_cert_to_DER_cert(cacert_pem)
1455 with open(CAFILE_NEURONIO) as f:
1456 neuronio_pem = f.read()
1457 neuronio_der = ssl.PEM_cert_to_DER_cert(neuronio_pem)
1458
1459 # test PEM
Christian Heimesa170fa12017-09-15 20:27:30 +02001460 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001461 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 0)
1462 ctx.load_verify_locations(cadata=cacert_pem)
1463 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 1)
1464 ctx.load_verify_locations(cadata=neuronio_pem)
1465 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1466 # cert already in hash table
1467 ctx.load_verify_locations(cadata=neuronio_pem)
1468 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1469
1470 # combined
Christian Heimesa170fa12017-09-15 20:27:30 +02001471 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001472 combined = "\n".join((cacert_pem, neuronio_pem))
1473 ctx.load_verify_locations(cadata=combined)
1474 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1475
1476 # with junk around the certs
Christian Heimesa170fa12017-09-15 20:27:30 +02001477 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001478 combined = ["head", cacert_pem, "other", neuronio_pem, "again",
1479 neuronio_pem, "tail"]
1480 ctx.load_verify_locations(cadata="\n".join(combined))
1481 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1482
1483 # test DER
Christian Heimesa170fa12017-09-15 20:27:30 +02001484 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001485 ctx.load_verify_locations(cadata=cacert_der)
1486 ctx.load_verify_locations(cadata=neuronio_der)
1487 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1488 # cert already in hash table
1489 ctx.load_verify_locations(cadata=cacert_der)
1490 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1491
1492 # combined
Christian Heimesa170fa12017-09-15 20:27:30 +02001493 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001494 combined = b"".join((cacert_der, neuronio_der))
1495 ctx.load_verify_locations(cadata=combined)
1496 self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2)
1497
1498 # error cases
Christian Heimesa170fa12017-09-15 20:27:30 +02001499 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimesefff7062013-11-21 03:35:02 +01001500 self.assertRaises(TypeError, ctx.load_verify_locations, cadata=object)
1501
1502 with self.assertRaisesRegex(ssl.SSLError, "no start line"):
1503 ctx.load_verify_locations(cadata="broken")
1504 with self.assertRaisesRegex(ssl.SSLError, "not enough data"):
1505 ctx.load_verify_locations(cadata=b"broken")
1506
1507
Paul Monsonf3550692019-06-19 13:09:54 -07001508 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001509 def test_load_dh_params(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001510 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001511 ctx.load_dh_params(DHFILE)
1512 if os.name != 'nt':
1513 ctx.load_dh_params(BYTES_DHFILE)
1514 self.assertRaises(TypeError, ctx.load_dh_params)
1515 self.assertRaises(TypeError, ctx.load_dh_params, None)
1516 with self.assertRaises(FileNotFoundError) as cm:
Martin Panter407b62f2016-01-30 03:41:43 +00001517 ctx.load_dh_params(NONEXISTINGCERT)
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001518 self.assertEqual(cm.exception.errno, errno.ENOENT)
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001519 with self.assertRaises(ssl.SSLError) as cm:
Antoine Pitrou0e576f12011-12-22 10:03:38 +01001520 ctx.load_dh_params(CERTFILE)
1521
Antoine Pitroub0182c82010-10-12 20:09:02 +00001522 def test_session_stats(self):
1523 for proto in PROTOCOLS:
1524 ctx = ssl.SSLContext(proto)
1525 self.assertEqual(ctx.session_stats(), {
1526 'number': 0,
1527 'connect': 0,
1528 'connect_good': 0,
1529 'connect_renegotiate': 0,
1530 'accept': 0,
1531 'accept_good': 0,
1532 'accept_renegotiate': 0,
1533 'hits': 0,
1534 'misses': 0,
1535 'timeouts': 0,
1536 'cache_full': 0,
1537 })
1538
Antoine Pitrou664c2d12010-11-17 20:29:42 +00001539 def test_set_default_verify_paths(self):
1540 # There's not much we can do to test that it acts as expected,
1541 # so just check it doesn't crash or raise an exception.
Christian Heimesa170fa12017-09-15 20:27:30 +02001542 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou664c2d12010-11-17 20:29:42 +00001543 ctx.set_default_verify_paths()
1544
Antoine Pitrou501da612011-12-21 09:27:41 +01001545 @unittest.skipUnless(ssl.HAS_ECDH, "ECDH disabled on this OpenSSL build")
Antoine Pitrou923df6f2011-12-19 17:16:51 +01001546 def test_set_ecdh_curve(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001547 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou923df6f2011-12-19 17:16:51 +01001548 ctx.set_ecdh_curve("prime256v1")
1549 ctx.set_ecdh_curve(b"prime256v1")
1550 self.assertRaises(TypeError, ctx.set_ecdh_curve)
1551 self.assertRaises(TypeError, ctx.set_ecdh_curve, None)
1552 self.assertRaises(ValueError, ctx.set_ecdh_curve, "foo")
1553 self.assertRaises(ValueError, ctx.set_ecdh_curve, b"foo")
1554
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001555 @needs_sni
1556 def test_sni_callback(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001557 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001558
1559 # set_servername_callback expects a callable, or None
1560 self.assertRaises(TypeError, ctx.set_servername_callback)
1561 self.assertRaises(TypeError, ctx.set_servername_callback, 4)
1562 self.assertRaises(TypeError, ctx.set_servername_callback, "")
1563 self.assertRaises(TypeError, ctx.set_servername_callback, ctx)
1564
1565 def dummycallback(sock, servername, ctx):
1566 pass
1567 ctx.set_servername_callback(None)
1568 ctx.set_servername_callback(dummycallback)
1569
1570 @needs_sni
1571 def test_sni_callback_refcycle(self):
1572 # Reference cycles through the servername callback are detected
1573 # and cleared.
Christian Heimesa170fa12017-09-15 20:27:30 +02001574 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01001575 def dummycallback(sock, servername, ctx, cycle=ctx):
1576 pass
1577 ctx.set_servername_callback(dummycallback)
1578 wr = weakref.ref(ctx)
1579 del ctx, dummycallback
1580 gc.collect()
1581 self.assertIs(wr(), None)
1582
Christian Heimes9a5395a2013-06-17 15:44:12 +02001583 def test_cert_store_stats(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001584 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001585 self.assertEqual(ctx.cert_store_stats(),
1586 {'x509_ca': 0, 'crl': 0, 'x509': 0})
1587 ctx.load_cert_chain(CERTFILE)
1588 self.assertEqual(ctx.cert_store_stats(),
1589 {'x509_ca': 0, 'crl': 0, 'x509': 0})
1590 ctx.load_verify_locations(CERTFILE)
1591 self.assertEqual(ctx.cert_store_stats(),
1592 {'x509_ca': 0, 'crl': 0, 'x509': 1})
Martin Panterb55f8b72016-01-14 12:53:56 +00001593 ctx.load_verify_locations(CAFILE_CACERT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001594 self.assertEqual(ctx.cert_store_stats(),
1595 {'x509_ca': 1, 'crl': 0, 'x509': 2})
1596
1597 def test_get_ca_certs(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001598 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001599 self.assertEqual(ctx.get_ca_certs(), [])
1600 # CERTFILE is not flagged as X509v3 Basic Constraints: CA:TRUE
1601 ctx.load_verify_locations(CERTFILE)
1602 self.assertEqual(ctx.get_ca_certs(), [])
Martin Panterb55f8b72016-01-14 12:53:56 +00001603 # but CAFILE_CACERT is a CA cert
1604 ctx.load_verify_locations(CAFILE_CACERT)
Christian Heimes9a5395a2013-06-17 15:44:12 +02001605 self.assertEqual(ctx.get_ca_certs(),
1606 [{'issuer': ((('organizationName', 'Root CA'),),
1607 (('organizationalUnitName', 'http://www.cacert.org'),),
1608 (('commonName', 'CA Cert Signing Authority'),),
1609 (('emailAddress', 'support@cacert.org'),)),
1610 'notAfter': asn1time('Mar 29 12:29:49 2033 GMT'),
1611 'notBefore': asn1time('Mar 30 12:29:49 2003 GMT'),
1612 'serialNumber': '00',
Christian Heimesbd3a7f92013-11-21 03:40:15 +01001613 'crlDistributionPoints': ('https://www.cacert.org/revoke.crl',),
Christian Heimes9a5395a2013-06-17 15:44:12 +02001614 'subject': ((('organizationName', 'Root CA'),),
1615 (('organizationalUnitName', 'http://www.cacert.org'),),
1616 (('commonName', 'CA Cert Signing Authority'),),
1617 (('emailAddress', 'support@cacert.org'),)),
1618 'version': 3}])
1619
Martin Panterb55f8b72016-01-14 12:53:56 +00001620 with open(CAFILE_CACERT) as f:
Christian Heimes9a5395a2013-06-17 15:44:12 +02001621 pem = f.read()
1622 der = ssl.PEM_cert_to_DER_cert(pem)
1623 self.assertEqual(ctx.get_ca_certs(True), [der])
1624
Christian Heimes72d28502013-11-23 13:56:58 +01001625 def test_load_default_certs(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001626 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001627 ctx.load_default_certs()
1628
Christian Heimesa170fa12017-09-15 20:27:30 +02001629 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001630 ctx.load_default_certs(ssl.Purpose.SERVER_AUTH)
1631 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.CLIENT_AUTH)
1635
Christian Heimesa170fa12017-09-15 20:27:30 +02001636 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes72d28502013-11-23 13:56:58 +01001637 self.assertRaises(TypeError, ctx.load_default_certs, None)
1638 self.assertRaises(TypeError, ctx.load_default_certs, 'SERVER_AUTH')
1639
Benjamin Peterson91244e02014-10-03 18:17:15 -04001640 @unittest.skipIf(sys.platform == "win32", "not-Windows specific")
Christian Heimes598894f2016-09-05 23:19:05 +02001641 @unittest.skipIf(IS_LIBRESSL, "LibreSSL doesn't support env vars")
Benjamin Peterson5915b0f2014-10-03 17:27:05 -04001642 def test_load_default_certs_env(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001643 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Hai Shia7f5d932020-08-04 00:41:24 +08001644 with os_helper.EnvironmentVarGuard() as env:
Benjamin Peterson5915b0f2014-10-03 17:27:05 -04001645 env["SSL_CERT_DIR"] = CAPATH
1646 env["SSL_CERT_FILE"] = CERTFILE
1647 ctx.load_default_certs()
1648 self.assertEqual(ctx.cert_store_stats(), {"crl": 0, "x509": 1, "x509_ca": 0})
1649
Benjamin Peterson91244e02014-10-03 18:17:15 -04001650 @unittest.skipUnless(sys.platform == "win32", "Windows specific")
Steve Dower68d663c2017-07-17 11:15:48 +02001651 @unittest.skipIf(hasattr(sys, "gettotalrefcount"), "Debug build does not share environment between CRTs")
Benjamin Peterson91244e02014-10-03 18:17:15 -04001652 def test_load_default_certs_env_windows(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001653 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Benjamin Peterson91244e02014-10-03 18:17:15 -04001654 ctx.load_default_certs()
1655 stats = ctx.cert_store_stats()
1656
Christian Heimesa170fa12017-09-15 20:27:30 +02001657 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Hai Shia7f5d932020-08-04 00:41:24 +08001658 with os_helper.EnvironmentVarGuard() as env:
Benjamin Peterson91244e02014-10-03 18:17:15 -04001659 env["SSL_CERT_DIR"] = CAPATH
1660 env["SSL_CERT_FILE"] = CERTFILE
1661 ctx.load_default_certs()
1662 stats["x509"] += 1
1663 self.assertEqual(ctx.cert_store_stats(), stats)
1664
Christian Heimes358cfd42016-09-10 22:43:48 +02001665 def _assert_context_options(self, ctx):
1666 self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
1667 if OP_NO_COMPRESSION != 0:
1668 self.assertEqual(ctx.options & OP_NO_COMPRESSION,
1669 OP_NO_COMPRESSION)
1670 if OP_SINGLE_DH_USE != 0:
1671 self.assertEqual(ctx.options & OP_SINGLE_DH_USE,
1672 OP_SINGLE_DH_USE)
1673 if OP_SINGLE_ECDH_USE != 0:
1674 self.assertEqual(ctx.options & OP_SINGLE_ECDH_USE,
1675 OP_SINGLE_ECDH_USE)
1676 if OP_CIPHER_SERVER_PREFERENCE != 0:
1677 self.assertEqual(ctx.options & OP_CIPHER_SERVER_PREFERENCE,
1678 OP_CIPHER_SERVER_PREFERENCE)
1679
Christian Heimes4c05b472013-11-23 15:58:30 +01001680 def test_create_default_context(self):
1681 ctx = ssl.create_default_context()
Christian Heimes358cfd42016-09-10 22:43:48 +02001682
Christian Heimesa170fa12017-09-15 20:27:30 +02001683 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
Christian Heimes4c05b472013-11-23 15:58:30 +01001684 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001685 self.assertTrue(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001686 self._assert_context_options(ctx)
1687
Christian Heimes4c05b472013-11-23 15:58:30 +01001688 with open(SIGNING_CA) as f:
1689 cadata = f.read()
1690 ctx = ssl.create_default_context(cafile=SIGNING_CA, capath=CAPATH,
1691 cadata=cadata)
Christian Heimesa170fa12017-09-15 20:27:30 +02001692 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
Christian Heimes4c05b472013-11-23 15:58:30 +01001693 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes358cfd42016-09-10 22:43:48 +02001694 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001695
1696 ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
Christian Heimesa170fa12017-09-15 20:27:30 +02001697 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
Christian Heimes4c05b472013-11-23 15:58:30 +01001698 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001699 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001700
Christian Heimes67986f92013-11-23 22:43:47 +01001701 def test__create_stdlib_context(self):
1702 ctx = ssl._create_stdlib_context()
Christian Heimesa170fa12017-09-15 20:27:30 +02001703 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
Christian Heimes67986f92013-11-23 22:43:47 +01001704 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001705 self.assertFalse(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001706 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001707
1708 ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1)
1709 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
1710 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001711 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001712
1713 ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1,
Christian Heimesa02c69a2013-12-02 20:59:28 +01001714 cert_reqs=ssl.CERT_REQUIRED,
1715 check_hostname=True)
Christian Heimes67986f92013-11-23 22:43:47 +01001716 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
1717 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimesa02c69a2013-12-02 20:59:28 +01001718 self.assertTrue(ctx.check_hostname)
Christian Heimes358cfd42016-09-10 22:43:48 +02001719 self._assert_context_options(ctx)
Christian Heimes67986f92013-11-23 22:43:47 +01001720
1721 ctx = ssl._create_stdlib_context(purpose=ssl.Purpose.CLIENT_AUTH)
Christian Heimesa170fa12017-09-15 20:27:30 +02001722 self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
Christian Heimes67986f92013-11-23 22:43:47 +01001723 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes358cfd42016-09-10 22:43:48 +02001724 self._assert_context_options(ctx)
Christian Heimes4c05b472013-11-23 15:58:30 +01001725
Christian Heimes1aa9a752013-12-02 02:41:19 +01001726 def test_check_hostname(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02001727 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001728 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001729 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001730
Christian Heimese82c0342017-09-15 20:29:57 +02001731 # Auto set CERT_REQUIRED
1732 ctx.check_hostname = True
1733 self.assertTrue(ctx.check_hostname)
1734 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1735 ctx.check_hostname = False
Christian Heimes1aa9a752013-12-02 02:41:19 +01001736 ctx.verify_mode = ssl.CERT_REQUIRED
1737 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001738 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001739
Christian Heimese82c0342017-09-15 20:29:57 +02001740 # Changing verify_mode does not affect check_hostname
1741 ctx.check_hostname = False
1742 ctx.verify_mode = ssl.CERT_NONE
1743 ctx.check_hostname = False
1744 self.assertFalse(ctx.check_hostname)
1745 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1746 # Auto set
Christian Heimes1aa9a752013-12-02 02:41:19 +01001747 ctx.check_hostname = True
1748 self.assertTrue(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001749 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1750
1751 ctx.check_hostname = False
1752 ctx.verify_mode = ssl.CERT_OPTIONAL
1753 ctx.check_hostname = False
1754 self.assertFalse(ctx.check_hostname)
1755 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1756 # keep CERT_OPTIONAL
1757 ctx.check_hostname = True
1758 self.assertTrue(ctx.check_hostname)
1759 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001760
1761 # Cannot set CERT_NONE with check_hostname enabled
1762 with self.assertRaises(ValueError):
1763 ctx.verify_mode = ssl.CERT_NONE
1764 ctx.check_hostname = False
1765 self.assertFalse(ctx.check_hostname)
Christian Heimese82c0342017-09-15 20:29:57 +02001766 ctx.verify_mode = ssl.CERT_NONE
1767 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
Christian Heimes1aa9a752013-12-02 02:41:19 +01001768
Christian Heimes5fe668c2016-09-12 00:01:11 +02001769 def test_context_client_server(self):
1770 # PROTOCOL_TLS_CLIENT has sane defaults
1771 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1772 self.assertTrue(ctx.check_hostname)
1773 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1774
1775 # PROTOCOL_TLS_SERVER has different but also sane defaults
1776 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1777 self.assertFalse(ctx.check_hostname)
1778 self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
1779
Christian Heimes4df60f12017-09-15 20:26:05 +02001780 def test_context_custom_class(self):
1781 class MySSLSocket(ssl.SSLSocket):
1782 pass
1783
1784 class MySSLObject(ssl.SSLObject):
1785 pass
1786
1787 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1788 ctx.sslsocket_class = MySSLSocket
1789 ctx.sslobject_class = MySSLObject
1790
1791 with ctx.wrap_socket(socket.socket(), server_side=True) as sock:
1792 self.assertIsInstance(sock, MySSLSocket)
1793 obj = ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO())
1794 self.assertIsInstance(obj, MySSLObject)
1795
Christian Heimes78c7d522019-06-03 21:00:10 +02001796 @unittest.skipUnless(IS_OPENSSL_1_1_1, "Test requires OpenSSL 1.1.1")
1797 def test_num_tickest(self):
1798 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
1799 self.assertEqual(ctx.num_tickets, 2)
1800 ctx.num_tickets = 1
1801 self.assertEqual(ctx.num_tickets, 1)
1802 ctx.num_tickets = 0
1803 self.assertEqual(ctx.num_tickets, 0)
1804 with self.assertRaises(ValueError):
1805 ctx.num_tickets = -1
1806 with self.assertRaises(TypeError):
1807 ctx.num_tickets = None
1808
1809 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1810 self.assertEqual(ctx.num_tickets, 2)
1811 with self.assertRaises(ValueError):
1812 ctx.num_tickets = 1
1813
Antoine Pitrou152efa22010-05-16 18:19:27 +00001814
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001815class SSLErrorTests(unittest.TestCase):
1816
1817 def test_str(self):
1818 # The str() of a SSLError doesn't include the errno
1819 e = ssl.SSLError(1, "foo")
1820 self.assertEqual(str(e), "foo")
1821 self.assertEqual(e.errno, 1)
1822 # Same for a subclass
1823 e = ssl.SSLZeroReturnError(1, "foo")
1824 self.assertEqual(str(e), "foo")
1825 self.assertEqual(e.errno, 1)
1826
Paul Monsonf3550692019-06-19 13:09:54 -07001827 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001828 def test_lib_reason(self):
1829 # Test the library and reason attributes
Christian Heimesa170fa12017-09-15 20:27:30 +02001830 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001831 with self.assertRaises(ssl.SSLError) as cm:
1832 ctx.load_dh_params(CERTFILE)
1833 self.assertEqual(cm.exception.library, 'PEM')
1834 self.assertEqual(cm.exception.reason, 'NO_START_LINE')
1835 s = str(cm.exception)
1836 self.assertTrue(s.startswith("[PEM: NO_START_LINE] no start line"), s)
1837
1838 def test_subclass(self):
1839 # Check that the appropriate SSLError subclass is raised
1840 # (this only tests one of them)
Christian Heimesa170fa12017-09-15 20:27:30 +02001841 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1842 ctx.check_hostname = False
1843 ctx.verify_mode = ssl.CERT_NONE
Giampaolo Rodolaeb7e29f2019-04-09 00:34:02 +02001844 with socket.create_server(("127.0.0.1", 0)) as s:
1845 c = socket.create_connection(s.getsockname())
Antoine Pitroue1ceb502013-01-12 21:54:44 +01001846 c.setblocking(False)
1847 with ctx.wrap_socket(c, False, do_handshake_on_connect=False) as c:
Antoine Pitrou3b36fb12012-06-22 21:11:52 +02001848 with self.assertRaises(ssl.SSLWantReadError) as cm:
1849 c.do_handshake()
1850 s = str(cm.exception)
1851 self.assertTrue(s.startswith("The operation did not complete (read)"), s)
1852 # For compatibility
1853 self.assertEqual(cm.exception.errno, ssl.SSL_ERROR_WANT_READ)
1854
1855
Christian Heimes61d478c2018-01-27 15:51:38 +01001856 def test_bad_server_hostname(self):
1857 ctx = ssl.create_default_context()
1858 with self.assertRaises(ValueError):
1859 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1860 server_hostname="")
1861 with self.assertRaises(ValueError):
1862 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1863 server_hostname=".example.org")
Christian Heimesd02ac252018-03-25 12:36:13 +02001864 with self.assertRaises(TypeError):
1865 ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1866 server_hostname="example.org\x00evil.com")
Christian Heimes61d478c2018-01-27 15:51:38 +01001867
1868
Antoine Pitroub1fdf472014-10-05 20:41:53 +02001869class MemoryBIOTests(unittest.TestCase):
1870
1871 def test_read_write(self):
1872 bio = ssl.MemoryBIO()
1873 bio.write(b'foo')
1874 self.assertEqual(bio.read(), b'foo')
1875 self.assertEqual(bio.read(), b'')
1876 bio.write(b'foo')
1877 bio.write(b'bar')
1878 self.assertEqual(bio.read(), b'foobar')
1879 self.assertEqual(bio.read(), b'')
1880 bio.write(b'baz')
1881 self.assertEqual(bio.read(2), b'ba')
1882 self.assertEqual(bio.read(1), b'z')
1883 self.assertEqual(bio.read(1), b'')
1884
1885 def test_eof(self):
1886 bio = ssl.MemoryBIO()
1887 self.assertFalse(bio.eof)
1888 self.assertEqual(bio.read(), b'')
1889 self.assertFalse(bio.eof)
1890 bio.write(b'foo')
1891 self.assertFalse(bio.eof)
1892 bio.write_eof()
1893 self.assertFalse(bio.eof)
1894 self.assertEqual(bio.read(2), b'fo')
1895 self.assertFalse(bio.eof)
1896 self.assertEqual(bio.read(1), b'o')
1897 self.assertTrue(bio.eof)
1898 self.assertEqual(bio.read(), b'')
1899 self.assertTrue(bio.eof)
1900
1901 def test_pending(self):
1902 bio = ssl.MemoryBIO()
1903 self.assertEqual(bio.pending, 0)
1904 bio.write(b'foo')
1905 self.assertEqual(bio.pending, 3)
1906 for i in range(3):
1907 bio.read(1)
1908 self.assertEqual(bio.pending, 3-i-1)
1909 for i in range(3):
1910 bio.write(b'x')
1911 self.assertEqual(bio.pending, i+1)
1912 bio.read()
1913 self.assertEqual(bio.pending, 0)
1914
1915 def test_buffer_types(self):
1916 bio = ssl.MemoryBIO()
1917 bio.write(b'foo')
1918 self.assertEqual(bio.read(), b'foo')
1919 bio.write(bytearray(b'bar'))
1920 self.assertEqual(bio.read(), b'bar')
1921 bio.write(memoryview(b'baz'))
1922 self.assertEqual(bio.read(), b'baz')
1923
1924 def test_error_types(self):
1925 bio = ssl.MemoryBIO()
1926 self.assertRaises(TypeError, bio.write, 'foo')
1927 self.assertRaises(TypeError, bio.write, None)
1928 self.assertRaises(TypeError, bio.write, True)
1929 self.assertRaises(TypeError, bio.write, 1)
1930
1931
Christian Heimes9d50ab52018-02-27 10:17:30 +01001932class SSLObjectTests(unittest.TestCase):
1933 def test_private_init(self):
1934 bio = ssl.MemoryBIO()
1935 with self.assertRaisesRegex(TypeError, "public constructor"):
1936 ssl.SSLObject(bio, bio)
1937
Nathaniel J. Smithc0da5822018-09-21 21:44:12 -07001938 def test_unwrap(self):
1939 client_ctx, server_ctx, hostname = testing_context()
1940 c_in = ssl.MemoryBIO()
1941 c_out = ssl.MemoryBIO()
1942 s_in = ssl.MemoryBIO()
1943 s_out = ssl.MemoryBIO()
1944 client = client_ctx.wrap_bio(c_in, c_out, server_hostname=hostname)
1945 server = server_ctx.wrap_bio(s_in, s_out, server_side=True)
1946
1947 # Loop on the handshake for a bit to get it settled
1948 for _ in range(5):
1949 try:
1950 client.do_handshake()
1951 except ssl.SSLWantReadError:
1952 pass
1953 if c_out.pending:
1954 s_in.write(c_out.read())
1955 try:
1956 server.do_handshake()
1957 except ssl.SSLWantReadError:
1958 pass
1959 if s_out.pending:
1960 c_in.write(s_out.read())
1961 # Now the handshakes should be complete (don't raise WantReadError)
1962 client.do_handshake()
1963 server.do_handshake()
1964
1965 # Now if we unwrap one side unilaterally, it should send close-notify
1966 # and raise WantReadError:
1967 with self.assertRaises(ssl.SSLWantReadError):
1968 client.unwrap()
1969
1970 # But server.unwrap() does not raise, because it reads the client's
1971 # close-notify:
1972 s_in.write(c_out.read())
1973 server.unwrap()
1974
1975 # And now that the client gets the server's close-notify, it doesn't
1976 # raise either.
1977 c_in.write(s_out.read())
1978 client.unwrap()
Christian Heimes9d50ab52018-02-27 10:17:30 +01001979
Martin Panter3840b2a2016-03-27 01:53:46 +00001980class SimpleBackgroundTests(unittest.TestCase):
Martin Panter3840b2a2016-03-27 01:53:46 +00001981 """Tests that connect to a simple server running in the background"""
1982
1983 def setUp(self):
1984 server = ThreadedEchoServer(SIGNED_CERTFILE)
1985 self.server_addr = (HOST, server.port)
1986 server.__enter__()
1987 self.addCleanup(server.__exit__, None, None, None)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001988
Antoine Pitrou480a1242010-04-28 21:37:09 +00001989 def test_connect(self):
Christian Heimesd0486372016-09-10 23:23:33 +02001990 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001991 cert_reqs=ssl.CERT_NONE) as s:
1992 s.connect(self.server_addr)
1993 self.assertEqual({}, s.getpeercert())
Christian Heimesa5d07652016-09-24 10:48:05 +02001994 self.assertFalse(s.server_side)
Antoine Pitrou350c7222010-09-09 13:31:46 +00001995
Martin Panter3840b2a2016-03-27 01:53:46 +00001996 # this should succeed because we specify the root cert
Christian Heimesd0486372016-09-10 23:23:33 +02001997 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00001998 cert_reqs=ssl.CERT_REQUIRED,
1999 ca_certs=SIGNING_CA) as s:
2000 s.connect(self.server_addr)
2001 self.assertTrue(s.getpeercert())
Christian Heimesa5d07652016-09-24 10:48:05 +02002002 self.assertFalse(s.server_side)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002003
Martin Panter3840b2a2016-03-27 01:53:46 +00002004 def test_connect_fail(self):
2005 # This should fail because we have no verification certs. Connection
2006 # failure crashes ThreadedEchoServer, so run this in an independent
2007 # test method.
Christian Heimesd0486372016-09-10 23:23:33 +02002008 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002009 cert_reqs=ssl.CERT_REQUIRED)
2010 self.addCleanup(s.close)
2011 self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
2012 s.connect, self.server_addr)
Antoine Pitrou152efa22010-05-16 18:19:27 +00002013
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002014 def test_connect_ex(self):
2015 # Issue #11326: check connect_ex() implementation
Christian Heimesd0486372016-09-10 23:23:33 +02002016 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002017 cert_reqs=ssl.CERT_REQUIRED,
2018 ca_certs=SIGNING_CA)
2019 self.addCleanup(s.close)
2020 self.assertEqual(0, s.connect_ex(self.server_addr))
2021 self.assertTrue(s.getpeercert())
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002022
2023 def test_non_blocking_connect_ex(self):
2024 # Issue #11326: non-blocking connect_ex() should allow handshake
2025 # to proceed after the socket gets ready.
Christian Heimesd0486372016-09-10 23:23:33 +02002026 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002027 cert_reqs=ssl.CERT_REQUIRED,
2028 ca_certs=SIGNING_CA,
2029 do_handshake_on_connect=False)
2030 self.addCleanup(s.close)
2031 s.setblocking(False)
2032 rc = s.connect_ex(self.server_addr)
2033 # EWOULDBLOCK under Windows, EINPROGRESS elsewhere
2034 self.assertIn(rc, (0, errno.EINPROGRESS, errno.EWOULDBLOCK))
2035 # Wait for connect to finish
2036 select.select([], [s], [], 5.0)
2037 # Non-blocking handshake
2038 while True:
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002039 try:
Martin Panter3840b2a2016-03-27 01:53:46 +00002040 s.do_handshake()
2041 break
2042 except ssl.SSLWantReadError:
2043 select.select([s], [], [], 5.0)
2044 except ssl.SSLWantWriteError:
Antoine Pitroue93bf7a2011-02-26 23:24:06 +00002045 select.select([], [s], [], 5.0)
Martin Panter3840b2a2016-03-27 01:53:46 +00002046 # SSL established
2047 self.assertTrue(s.getpeercert())
Antoine Pitrou40f12ab2012-12-28 19:03:43 +01002048
Antoine Pitrou152efa22010-05-16 18:19:27 +00002049 def test_connect_with_context(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002050 # Same as test_connect, but with a separately created context
Christian Heimesa170fa12017-09-15 20:27:30 +02002051 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Martin Panter3840b2a2016-03-27 01:53:46 +00002052 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2053 s.connect(self.server_addr)
2054 self.assertEqual({}, s.getpeercert())
2055 # Same with a server hostname
2056 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2057 server_hostname="dummy") as s:
2058 s.connect(self.server_addr)
2059 ctx.verify_mode = ssl.CERT_REQUIRED
2060 # This should succeed because we specify the root cert
2061 ctx.load_verify_locations(SIGNING_CA)
2062 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2063 s.connect(self.server_addr)
2064 cert = s.getpeercert()
2065 self.assertTrue(cert)
2066
2067 def test_connect_with_context_fail(self):
2068 # This should fail because we have no verification certs. Connection
2069 # failure crashes ThreadedEchoServer, so run this in an independent
2070 # test method.
Christian Heimesa170fa12017-09-15 20:27:30 +02002071 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Martin Panter3840b2a2016-03-27 01:53:46 +00002072 ctx.verify_mode = ssl.CERT_REQUIRED
2073 s = ctx.wrap_socket(socket.socket(socket.AF_INET))
2074 self.addCleanup(s.close)
2075 self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
2076 s.connect, self.server_addr)
Antoine Pitrou152efa22010-05-16 18:19:27 +00002077
2078 def test_connect_capath(self):
2079 # Verify server certificates using the `capath` argument
Antoine Pitrou467f28d2010-05-16 19:22:44 +00002080 # NOTE: the subject hashing algorithm has been changed between
2081 # OpenSSL 0.9.8n and 1.0.0, as a result the capath directory must
2082 # contain both versions of each certificate (same content, different
Antoine Pitroud7e4c1c2010-05-17 14:13:10 +00002083 # filename) for this test to be portable across OpenSSL releases.
Christian Heimesa170fa12017-09-15 20:27:30 +02002084 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Martin Panter3840b2a2016-03-27 01:53:46 +00002085 ctx.verify_mode = ssl.CERT_REQUIRED
2086 ctx.load_verify_locations(capath=CAPATH)
2087 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2088 s.connect(self.server_addr)
2089 cert = s.getpeercert()
2090 self.assertTrue(cert)
Christian Heimes529525f2018-05-23 22:24:45 +02002091
Martin Panter3840b2a2016-03-27 01:53:46 +00002092 # Same with a bytes `capath` argument
Christian Heimesa170fa12017-09-15 20:27:30 +02002093 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Martin Panter3840b2a2016-03-27 01:53:46 +00002094 ctx.verify_mode = ssl.CERT_REQUIRED
2095 ctx.load_verify_locations(capath=BYTES_CAPATH)
2096 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2097 s.connect(self.server_addr)
2098 cert = s.getpeercert()
2099 self.assertTrue(cert)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002100
Christian Heimesefff7062013-11-21 03:35:02 +01002101 def test_connect_cadata(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002102 with open(SIGNING_CA) as f:
Christian Heimesefff7062013-11-21 03:35:02 +01002103 pem = f.read()
2104 der = ssl.PEM_cert_to_DER_cert(pem)
Christian Heimesa170fa12017-09-15 20:27:30 +02002105 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Martin Panter3840b2a2016-03-27 01:53:46 +00002106 ctx.verify_mode = ssl.CERT_REQUIRED
2107 ctx.load_verify_locations(cadata=pem)
2108 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2109 s.connect(self.server_addr)
2110 cert = s.getpeercert()
2111 self.assertTrue(cert)
Christian Heimesefff7062013-11-21 03:35:02 +01002112
Martin Panter3840b2a2016-03-27 01:53:46 +00002113 # same with DER
Christian Heimesa170fa12017-09-15 20:27:30 +02002114 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Martin Panter3840b2a2016-03-27 01:53:46 +00002115 ctx.verify_mode = ssl.CERT_REQUIRED
2116 ctx.load_verify_locations(cadata=der)
2117 with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
2118 s.connect(self.server_addr)
2119 cert = s.getpeercert()
2120 self.assertTrue(cert)
Christian Heimesefff7062013-11-21 03:35:02 +01002121
Antoine Pitroue3220242010-04-24 11:13:53 +00002122 @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
2123 def test_makefile_close(self):
2124 # Issue #5238: creating a file-like object with makefile() shouldn't
2125 # delay closing the underlying "real socket" (here tested with its
2126 # file descriptor, hence skipping the test under Windows).
Christian Heimesd0486372016-09-10 23:23:33 +02002127 ss = test_wrap_socket(socket.socket(socket.AF_INET))
Martin Panter3840b2a2016-03-27 01:53:46 +00002128 ss.connect(self.server_addr)
2129 fd = ss.fileno()
2130 f = ss.makefile()
2131 f.close()
2132 # The fd is still open
2133 os.read(fd, 0)
2134 # Closing the SSL socket should close the fd too
2135 ss.close()
2136 gc.collect()
2137 with self.assertRaises(OSError) as e:
Antoine Pitroue3220242010-04-24 11:13:53 +00002138 os.read(fd, 0)
Martin Panter3840b2a2016-03-27 01:53:46 +00002139 self.assertEqual(e.exception.errno, errno.EBADF)
Antoine Pitroue3220242010-04-24 11:13:53 +00002140
Antoine Pitrou480a1242010-04-28 21:37:09 +00002141 def test_non_blocking_handshake(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002142 s = socket.socket(socket.AF_INET)
2143 s.connect(self.server_addr)
2144 s.setblocking(False)
Christian Heimesd0486372016-09-10 23:23:33 +02002145 s = test_wrap_socket(s,
Martin Panter3840b2a2016-03-27 01:53:46 +00002146 cert_reqs=ssl.CERT_NONE,
2147 do_handshake_on_connect=False)
2148 self.addCleanup(s.close)
2149 count = 0
2150 while True:
2151 try:
2152 count += 1
2153 s.do_handshake()
2154 break
2155 except ssl.SSLWantReadError:
2156 select.select([s], [], [])
2157 except ssl.SSLWantWriteError:
2158 select.select([], [s], [])
2159 if support.verbose:
2160 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002161
Antoine Pitrou480a1242010-04-28 21:37:09 +00002162 def test_get_server_certificate(self):
Martin Panter3840b2a2016-03-27 01:53:46 +00002163 _test_get_server_certificate(self, *self.server_addr, cert=SIGNING_CA)
Antoine Pitrou5aefa662011-04-28 19:24:46 +02002164
Martin Panter3840b2a2016-03-27 01:53:46 +00002165 def test_get_server_certificate_fail(self):
2166 # Connection failure crashes ThreadedEchoServer, so run this in an
2167 # independent test method
2168 _test_get_server_certificate_fail(self, *self.server_addr)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002169
Antoine Pitrouf4c7bad2010-08-15 23:02:22 +00002170 def test_ciphers(self):
Christian Heimesd0486372016-09-10 23:23:33 +02002171 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002172 cert_reqs=ssl.CERT_NONE, ciphers="ALL") as s:
2173 s.connect(self.server_addr)
Christian Heimesd0486372016-09-10 23:23:33 +02002174 with test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002175 cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT") as s:
2176 s.connect(self.server_addr)
2177 # Error checking can happen at instantiation or when connecting
2178 with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
2179 with socket.socket(socket.AF_INET) as sock:
Christian Heimesd0486372016-09-10 23:23:33 +02002180 s = test_wrap_socket(sock,
Martin Panter3840b2a2016-03-27 01:53:46 +00002181 cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
2182 s.connect(self.server_addr)
Antoine Pitroufec12ff2010-04-21 19:46:23 +00002183
Christian Heimes9a5395a2013-06-17 15:44:12 +02002184 def test_get_ca_certs_capath(self):
2185 # capath certs are loaded on request
Christian Heimesa170fa12017-09-15 20:27:30 +02002186 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Martin Panter3840b2a2016-03-27 01:53:46 +00002187 ctx.load_verify_locations(capath=CAPATH)
2188 self.assertEqual(ctx.get_ca_certs(), [])
Christian Heimesa170fa12017-09-15 20:27:30 +02002189 with ctx.wrap_socket(socket.socket(socket.AF_INET),
2190 server_hostname='localhost') as s:
Martin Panter3840b2a2016-03-27 01:53:46 +00002191 s.connect(self.server_addr)
2192 cert = s.getpeercert()
2193 self.assertTrue(cert)
2194 self.assertEqual(len(ctx.get_ca_certs()), 1)
Christian Heimes9a5395a2013-06-17 15:44:12 +02002195
Christian Heimes575596e2013-12-15 21:49:17 +01002196 @needs_sni
Christian Heimes8e7f3942013-12-05 07:41:08 +01002197 def test_context_setget(self):
2198 # Check that the context of a connected socket can be replaced.
Christian Heimesa170fa12017-09-15 20:27:30 +02002199 ctx1 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2200 ctx1.load_verify_locations(capath=CAPATH)
2201 ctx2 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2202 ctx2.load_verify_locations(capath=CAPATH)
Martin Panter3840b2a2016-03-27 01:53:46 +00002203 s = socket.socket(socket.AF_INET)
Christian Heimesa170fa12017-09-15 20:27:30 +02002204 with ctx1.wrap_socket(s, server_hostname='localhost') as ss:
Martin Panter3840b2a2016-03-27 01:53:46 +00002205 ss.connect(self.server_addr)
2206 self.assertIs(ss.context, ctx1)
2207 self.assertIs(ss._sslobj.context, ctx1)
2208 ss.context = ctx2
2209 self.assertIs(ss.context, ctx2)
2210 self.assertIs(ss._sslobj.context, ctx2)
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002211
2212 def ssl_io_loop(self, sock, incoming, outgoing, func, *args, **kwargs):
2213 # A simple IO loop. Call func(*args) depending on the error we get
2214 # (WANT_READ or WANT_WRITE) move data between the socket and the BIOs.
Victor Stinner0d63bac2019-12-11 11:30:03 +01002215 timeout = kwargs.get('timeout', support.SHORT_TIMEOUT)
Victor Stinner50a72af2017-09-11 09:34:24 -07002216 deadline = time.monotonic() + timeout
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002217 count = 0
2218 while True:
Victor Stinner50a72af2017-09-11 09:34:24 -07002219 if time.monotonic() > deadline:
2220 self.fail("timeout")
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002221 errno = None
2222 count += 1
2223 try:
2224 ret = func(*args)
2225 except ssl.SSLError as e:
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002226 if e.errno not in (ssl.SSL_ERROR_WANT_READ,
Martin Panter40b97ec2016-01-14 13:05:46 +00002227 ssl.SSL_ERROR_WANT_WRITE):
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002228 raise
2229 errno = e.errno
2230 # Get any data from the outgoing BIO irrespective of any error, and
2231 # send it to the socket.
2232 buf = outgoing.read()
2233 sock.sendall(buf)
2234 # If there's no error, we're done. For WANT_READ, we need to get
2235 # data from the socket and put it in the incoming BIO.
2236 if errno is None:
2237 break
2238 elif errno == ssl.SSL_ERROR_WANT_READ:
2239 buf = sock.recv(32768)
2240 if buf:
2241 incoming.write(buf)
2242 else:
2243 incoming.write_eof()
2244 if support.verbose:
2245 sys.stdout.write("Needed %d calls to complete %s().\n"
2246 % (count, func.__name__))
2247 return ret
2248
Martin Panter3840b2a2016-03-27 01:53:46 +00002249 def test_bio_handshake(self):
2250 sock = socket.socket(socket.AF_INET)
2251 self.addCleanup(sock.close)
2252 sock.connect(self.server_addr)
2253 incoming = ssl.MemoryBIO()
2254 outgoing = ssl.MemoryBIO()
Christian Heimesa170fa12017-09-15 20:27:30 +02002255 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2256 self.assertTrue(ctx.check_hostname)
2257 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
Martin Panter3840b2a2016-03-27 01:53:46 +00002258 ctx.load_verify_locations(SIGNING_CA)
Christian Heimesa170fa12017-09-15 20:27:30 +02002259 sslobj = ctx.wrap_bio(incoming, outgoing, False,
2260 SIGNED_CERTFILE_HOSTNAME)
Martin Panter3840b2a2016-03-27 01:53:46 +00002261 self.assertIs(sslobj._sslobj.owner, sslobj)
2262 self.assertIsNone(sslobj.cipher())
Christian Heimes68771112017-09-05 21:55:40 -07002263 self.assertIsNone(sslobj.version())
Christian Heimes01113fa2016-09-05 23:23:24 +02002264 self.assertIsNotNone(sslobj.shared_ciphers())
Martin Panter3840b2a2016-03-27 01:53:46 +00002265 self.assertRaises(ValueError, sslobj.getpeercert)
2266 if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
2267 self.assertIsNone(sslobj.get_channel_binding('tls-unique'))
2268 self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
2269 self.assertTrue(sslobj.cipher())
Christian Heimes01113fa2016-09-05 23:23:24 +02002270 self.assertIsNotNone(sslobj.shared_ciphers())
Christian Heimes68771112017-09-05 21:55:40 -07002271 self.assertIsNotNone(sslobj.version())
Martin Panter3840b2a2016-03-27 01:53:46 +00002272 self.assertTrue(sslobj.getpeercert())
2273 if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
2274 self.assertTrue(sslobj.get_channel_binding('tls-unique'))
2275 try:
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002276 self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
Martin Panter3840b2a2016-03-27 01:53:46 +00002277 except ssl.SSLSyscallError:
2278 # If the server shuts down the TCP connection without sending a
2279 # secure shutdown message, this is reported as SSL_ERROR_SYSCALL
2280 pass
2281 self.assertRaises(ssl.SSLError, sslobj.write, b'foo')
2282
2283 def test_bio_read_write_data(self):
2284 sock = socket.socket(socket.AF_INET)
2285 self.addCleanup(sock.close)
2286 sock.connect(self.server_addr)
2287 incoming = ssl.MemoryBIO()
2288 outgoing = ssl.MemoryBIO()
Christian Heimesa170fa12017-09-15 20:27:30 +02002289 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
Martin Panter3840b2a2016-03-27 01:53:46 +00002290 ctx.verify_mode = ssl.CERT_NONE
2291 sslobj = ctx.wrap_bio(incoming, outgoing, False)
2292 self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
2293 req = b'FOO\n'
2294 self.ssl_io_loop(sock, incoming, outgoing, sslobj.write, req)
2295 buf = self.ssl_io_loop(sock, incoming, outgoing, sslobj.read, 1024)
2296 self.assertEqual(buf, b'foo\n')
2297 self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
Antoine Pitroub1fdf472014-10-05 20:41:53 +02002298
2299
Martin Panter3840b2a2016-03-27 01:53:46 +00002300class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002301
Martin Panter3840b2a2016-03-27 01:53:46 +00002302 def test_timeout_connect_ex(self):
2303 # Issue #12065: on a timeout, connect_ex() should return the original
2304 # errno (mimicking the behaviour of non-SSL sockets).
Serhiy Storchakabfb1cf42020-04-29 10:36:20 +03002305 with socket_helper.transient_internet(REMOTE_HOST):
Christian Heimesd0486372016-09-10 23:23:33 +02002306 s = test_wrap_socket(socket.socket(socket.AF_INET),
Martin Panter3840b2a2016-03-27 01:53:46 +00002307 cert_reqs=ssl.CERT_REQUIRED,
2308 do_handshake_on_connect=False)
2309 self.addCleanup(s.close)
2310 s.settimeout(0.0000001)
2311 rc = s.connect_ex((REMOTE_HOST, 443))
2312 if rc == 0:
2313 self.skipTest("REMOTE_HOST responded too quickly")
Carl Meyer29c451c2021-03-27 15:52:28 -06002314 elif rc == errno.ENETUNREACH:
2315 self.skipTest("Network unreachable.")
Martin Panter3840b2a2016-03-27 01:53:46 +00002316 self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK))
2317
Serhiy Storchaka16994912020-04-25 10:06:29 +03002318 @unittest.skipUnless(socket_helper.IPV6_ENABLED, 'Needs IPv6')
Martin Panter3840b2a2016-03-27 01:53:46 +00002319 def test_get_server_certificate_ipv6(self):
Serhiy Storchakabfb1cf42020-04-29 10:36:20 +03002320 with socket_helper.transient_internet('ipv6.google.com'):
Martin Panter3840b2a2016-03-27 01:53:46 +00002321 _test_get_server_certificate(self, 'ipv6.google.com', 443)
2322 _test_get_server_certificate_fail(self, 'ipv6.google.com', 443)
2323
Martin Panter3840b2a2016-03-27 01:53:46 +00002324
2325def _test_get_server_certificate(test, host, port, cert=None):
2326 pem = ssl.get_server_certificate((host, port))
2327 if not pem:
2328 test.fail("No server certificate on %s:%s!" % (host, port))
2329
2330 pem = ssl.get_server_certificate((host, port), ca_certs=cert)
2331 if not pem:
2332 test.fail("No server certificate on %s:%s!" % (host, port))
2333 if support.verbose:
2334 sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem))
2335
2336def _test_get_server_certificate_fail(test, host, port):
2337 try:
2338 pem = ssl.get_server_certificate((host, port), ca_certs=CERTFILE)
2339 except ssl.SSLError as x:
2340 #should fail
2341 if support.verbose:
2342 sys.stdout.write("%s\n" % x)
2343 else:
2344 test.fail("Got server certificate %s for %s:%s!" % (pem, host, port))
2345
2346
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002347from test.ssl_servers import make_https_server
Antoine Pitrou803e6d62010-10-13 10:36:15 +00002348
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002349class ThreadedEchoServer(threading.Thread):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002350
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002351 class ConnectionHandler(threading.Thread):
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002352
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002353 """A mildly complicated class, because we want it to work both
2354 with and without the SSL wrapper around the socket connection, so
2355 that we can test the STARTTLS functionality."""
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002356
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002357 def __init__(self, server, connsock, addr):
2358 self.server = server
2359 self.running = False
2360 self.sock = connsock
2361 self.addr = addr
Serhiy Storchaka5eca7f32019-09-01 12:12:52 +03002362 self.sock.setblocking(True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002363 self.sslconn = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002364 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +00002365 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002366
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002367 def wrap_conn(self):
2368 try:
2369 self.sslconn = self.server.context.wrap_socket(
2370 self.sock, server_side=True)
2371 self.server.selected_npn_protocols.append(self.sslconn.selected_npn_protocol())
2372 self.server.selected_alpn_protocols.append(self.sslconn.selected_alpn_protocol())
Paul Monsonfb7e7502019-05-15 15:38:55 -07002373 except (ConnectionResetError, BrokenPipeError, ConnectionAbortedError) as e:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002374 # We treat ConnectionResetError as though it were an
2375 # SSLError - OpenSSL on Ubuntu abruptly closes the
2376 # connection when asked to use an unsupported protocol.
2377 #
Christian Heimes529525f2018-05-23 22:24:45 +02002378 # BrokenPipeError is raised in TLS 1.3 mode, when OpenSSL
2379 # tries to send session tickets after handshake.
2380 # https://github.com/openssl/openssl/issues/6342
Paul Monsonfb7e7502019-05-15 15:38:55 -07002381 #
2382 # ConnectionAbortedError is raised in TLS 1.3 mode, when OpenSSL
2383 # tries to send session tickets after handshake when using WinSock.
Christian Heimes529525f2018-05-23 22:24:45 +02002384 self.server.conn_errors.append(str(e))
2385 if self.server.chatty:
2386 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
2387 self.running = False
2388 self.close()
2389 return False
2390 except (ssl.SSLError, OSError) as e:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002391 # OSError may occur with wrong protocols, e.g. both
2392 # sides use PROTOCOL_TLS_SERVER.
2393 #
2394 # XXX Various errors can have happened here, for example
2395 # a mismatching protocol version, an invalid certificate,
2396 # or a low-level bug. This should be made more discriminating.
2397 #
2398 # bpo-31323: Store the exception as string to prevent
2399 # a reference leak: server -> conn_errors -> exception
2400 # -> traceback -> self (ConnectionHandler) -> server
2401 self.server.conn_errors.append(str(e))
2402 if self.server.chatty:
2403 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
2404 self.running = False
2405 self.server.stop()
2406 self.close()
2407 return False
2408 else:
2409 self.server.shared_ciphers.append(self.sslconn.shared_ciphers())
2410 if self.server.context.verify_mode == ssl.CERT_REQUIRED:
2411 cert = self.sslconn.getpeercert()
2412 if support.verbose and self.server.chatty:
2413 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
2414 cert_binary = self.sslconn.getpeercert(True)
2415 if support.verbose and self.server.chatty:
2416 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
2417 cipher = self.sslconn.cipher()
2418 if support.verbose and self.server.chatty:
2419 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
2420 sys.stdout.write(" server: selected protocol is now "
2421 + str(self.sslconn.selected_npn_protocol()) + "\n")
2422 return True
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002423
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002424 def read(self):
2425 if self.sslconn:
2426 return self.sslconn.read()
2427 else:
2428 return self.sock.recv(1024)
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002429
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002430 def write(self, bytes):
2431 if self.sslconn:
2432 return self.sslconn.write(bytes)
2433 else:
2434 return self.sock.send(bytes)
2435
2436 def close(self):
2437 if self.sslconn:
2438 self.sslconn.close()
2439 else:
2440 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002441
Antoine Pitrou480a1242010-04-28 21:37:09 +00002442 def run(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002443 self.running = True
2444 if not self.server.starttls_server:
2445 if not self.wrap_conn():
2446 return
2447 while self.running:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002448 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002449 msg = self.read()
2450 stripped = msg.strip()
2451 if not stripped:
2452 # eof, so quit this handler
2453 self.running = False
2454 try:
2455 self.sock = self.sslconn.unwrap()
2456 except OSError:
2457 # Many tests shut the TCP connection down
2458 # without an SSL shutdown. This causes
2459 # unwrap() to raise OSError with errno=0!
2460 pass
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00002461 else:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002462 self.sslconn = None
2463 self.close()
2464 elif stripped == b'over':
2465 if support.verbose and self.server.connectionchatty:
2466 sys.stdout.write(" server: client closed connection\n")
2467 self.close()
2468 return
2469 elif (self.server.starttls_server and
2470 stripped == b'STARTTLS'):
2471 if support.verbose and self.server.connectionchatty:
2472 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
2473 self.write(b"OK\n")
2474 if not self.wrap_conn():
2475 return
2476 elif (self.server.starttls_server and self.sslconn
2477 and stripped == b'ENDTLS'):
2478 if support.verbose and self.server.connectionchatty:
2479 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
2480 self.write(b"OK\n")
2481 self.sock = self.sslconn.unwrap()
2482 self.sslconn = None
2483 if support.verbose and self.server.connectionchatty:
2484 sys.stdout.write(" server: connection is now unencrypted...\n")
2485 elif stripped == b'CB tls-unique':
2486 if support.verbose and self.server.connectionchatty:
2487 sys.stdout.write(" server: read CB tls-unique from client, sending our CB data...\n")
2488 data = self.sslconn.get_channel_binding("tls-unique")
2489 self.write(repr(data).encode("us-ascii") + b"\n")
Christian Heimes9fb051f2018-09-23 08:32:31 +02002490 elif stripped == b'PHA':
2491 if support.verbose and self.server.connectionchatty:
2492 sys.stdout.write(" server: initiating post handshake auth\n")
2493 try:
2494 self.sslconn.verify_client_post_handshake()
2495 except ssl.SSLError as e:
2496 self.write(repr(e).encode("us-ascii") + b"\n")
2497 else:
2498 self.write(b"OK\n")
2499 elif stripped == b'HASCERT':
2500 if self.sslconn.getpeercert() is not None:
2501 self.write(b'TRUE\n')
2502 else:
2503 self.write(b'FALSE\n')
2504 elif stripped == b'GETCERT':
2505 cert = self.sslconn.getpeercert()
2506 self.write(repr(cert).encode("us-ascii") + b"\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002507 else:
2508 if (support.verbose and
2509 self.server.connectionchatty):
2510 ctype = (self.sslconn and "encrypted") or "unencrypted"
2511 sys.stdout.write(" server: read %r (%s), sending back %r (%s)...\n"
2512 % (msg, ctype, msg.lower(), ctype))
2513 self.write(msg.lower())
Paul Monsonfb7e7502019-05-15 15:38:55 -07002514 except (ConnectionResetError, ConnectionAbortedError):
Christian Heimes529525f2018-05-23 22:24:45 +02002515 # XXX: OpenSSL 1.1.1 sometimes raises ConnectionResetError
2516 # when connection is not shut down gracefully.
2517 if self.server.chatty and support.verbose:
2518 sys.stdout.write(
2519 " Connection reset by peer: {}\n".format(
2520 self.addr)
2521 )
2522 self.close()
2523 self.running = False
Paul Monsonfb7e7502019-05-15 15:38:55 -07002524 except ssl.SSLError as err:
2525 # On Windows sometimes test_pha_required_nocert receives the
2526 # PEER_DID_NOT_RETURN_A_CERTIFICATE exception
2527 # before the 'tlsv13 alert certificate required' exception.
2528 # If the server is stopped when PEER_DID_NOT_RETURN_A_CERTIFICATE
2529 # is received test_pha_required_nocert fails with ConnectionResetError
2530 # because the underlying socket is closed
2531 if 'PEER_DID_NOT_RETURN_A_CERTIFICATE' == err.reason:
2532 if self.server.chatty and support.verbose:
2533 sys.stdout.write(err.args[1])
2534 # test_pha_required_nocert is expecting this exception
2535 raise ssl.SSLError('tlsv13 alert certificate required')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002536 except OSError:
2537 if self.server.chatty:
2538 handle_error("Test server failure:\n")
Bill Janssen2f5799b2008-06-29 00:08:12 +00002539 self.close()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002540 self.running = False
Christian Heimes529525f2018-05-23 22:24:45 +02002541
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002542 # normally, we'd just stop here, but for the test
2543 # harness, we want to stop the server
2544 self.server.stop()
Bill Janssen54cc54c2007-12-14 22:08:56 +00002545
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002546 def __init__(self, certificate=None, ssl_version=None,
2547 certreqs=None, cacerts=None,
2548 chatty=True, connectionchatty=False, starttls_server=False,
2549 npn_protocols=None, alpn_protocols=None,
2550 ciphers=None, context=None):
2551 if context:
2552 self.context = context
2553 else:
2554 self.context = ssl.SSLContext(ssl_version
2555 if ssl_version is not None
Christian Heimesa170fa12017-09-15 20:27:30 +02002556 else ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002557 self.context.verify_mode = (certreqs if certreqs is not None
2558 else ssl.CERT_NONE)
2559 if cacerts:
2560 self.context.load_verify_locations(cacerts)
2561 if certificate:
2562 self.context.load_cert_chain(certificate)
2563 if npn_protocols:
2564 self.context.set_npn_protocols(npn_protocols)
2565 if alpn_protocols:
2566 self.context.set_alpn_protocols(alpn_protocols)
2567 if ciphers:
2568 self.context.set_ciphers(ciphers)
2569 self.chatty = chatty
2570 self.connectionchatty = connectionchatty
2571 self.starttls_server = starttls_server
2572 self.sock = socket.socket()
Serhiy Storchaka16994912020-04-25 10:06:29 +03002573 self.port = socket_helper.bind_port(self.sock)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002574 self.flag = None
2575 self.active = False
2576 self.selected_npn_protocols = []
2577 self.selected_alpn_protocols = []
2578 self.shared_ciphers = []
2579 self.conn_errors = []
2580 threading.Thread.__init__(self)
2581 self.daemon = True
2582
2583 def __enter__(self):
2584 self.start(threading.Event())
2585 self.flag.wait()
2586 return self
2587
2588 def __exit__(self, *args):
2589 self.stop()
2590 self.join()
2591
2592 def start(self, flag=None):
2593 self.flag = flag
2594 threading.Thread.start(self)
2595
2596 def run(self):
2597 self.sock.settimeout(0.05)
2598 self.sock.listen()
2599 self.active = True
2600 if self.flag:
2601 # signal an event
2602 self.flag.set()
2603 while self.active:
2604 try:
2605 newconn, connaddr = self.sock.accept()
2606 if support.verbose and self.chatty:
2607 sys.stdout.write(' server: new connection from '
2608 + repr(connaddr) + '\n')
2609 handler = self.ConnectionHandler(self, newconn, connaddr)
2610 handler.start()
2611 handler.join()
Christian Heimes03c8ddd2020-11-20 09:26:07 +01002612 except TimeoutError:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002613 pass
2614 except KeyboardInterrupt:
2615 self.stop()
Christian Heimes529525f2018-05-23 22:24:45 +02002616 except BaseException as e:
2617 if support.verbose and self.chatty:
2618 sys.stdout.write(
2619 ' connection handling failed: ' + repr(e) + '\n')
2620
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002621 self.sock.close()
2622
2623 def stop(self):
2624 self.active = False
2625
2626class AsyncoreEchoServer(threading.Thread):
2627
2628 # this one's based on asyncore.dispatcher
2629
2630 class EchoServer (asyncore.dispatcher):
2631
2632 class ConnectionHandler(asyncore.dispatcher_with_send):
2633
2634 def __init__(self, conn, certfile):
2635 self.socket = test_wrap_socket(conn, server_side=True,
2636 certfile=certfile,
2637 do_handshake_on_connect=False)
2638 asyncore.dispatcher_with_send.__init__(self, self.socket)
2639 self._ssl_accepting = True
2640 self._do_ssl_handshake()
2641
2642 def readable(self):
2643 if isinstance(self.socket, ssl.SSLSocket):
2644 while self.socket.pending() > 0:
2645 self.handle_read_event()
2646 return True
2647
2648 def _do_ssl_handshake(self):
2649 try:
2650 self.socket.do_handshake()
2651 except (ssl.SSLWantReadError, ssl.SSLWantWriteError):
2652 return
2653 except ssl.SSLEOFError:
2654 return self.handle_close()
2655 except ssl.SSLError:
Bill Janssen54cc54c2007-12-14 22:08:56 +00002656 raise
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002657 except OSError as err:
2658 if err.args[0] == errno.ECONNABORTED:
2659 return self.handle_close()
2660 else:
2661 self._ssl_accepting = False
Bill Janssen54cc54c2007-12-14 22:08:56 +00002662
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002663 def handle_read(self):
2664 if self._ssl_accepting:
2665 self._do_ssl_handshake()
2666 else:
2667 data = self.recv(1024)
2668 if support.verbose:
2669 sys.stdout.write(" server: read %s from client\n" % repr(data))
2670 if not data:
2671 self.close()
2672 else:
2673 self.send(data.lower())
Bill Janssen54cc54c2007-12-14 22:08:56 +00002674
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002675 def handle_close(self):
2676 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002677 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002678 sys.stdout.write(" server: closed connection %s\n" % self.socket)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002679
2680 def handle_error(self):
2681 raise
2682
Trent Nelson78520002008-04-10 20:54:35 +00002683 def __init__(self, certfile):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002684 self.certfile = certfile
2685 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Serhiy Storchaka16994912020-04-25 10:06:29 +03002686 self.port = socket_helper.bind_port(sock, '')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002687 asyncore.dispatcher.__init__(self, sock)
2688 self.listen(5)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002689
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002690 def handle_accepted(self, sock_obj, addr):
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002691 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002692 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
2693 self.ConnectionHandler(sock_obj, self.certfile)
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002694
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002695 def handle_error(self):
2696 raise
Bill Janssen54cc54c2007-12-14 22:08:56 +00002697
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002698 def __init__(self, certfile):
2699 self.flag = None
2700 self.active = False
2701 self.server = self.EchoServer(certfile)
2702 self.port = self.server.port
2703 threading.Thread.__init__(self)
2704 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +00002705
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002706 def __str__(self):
2707 return "<%s %s>" % (self.__class__.__name__, self.server)
Bill Janssen54cc54c2007-12-14 22:08:56 +00002708
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002709 def __enter__(self):
2710 self.start(threading.Event())
2711 self.flag.wait()
2712 return self
Thomas Woutersed03b412007-08-28 21:37:11 +00002713
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002714 def __exit__(self, *args):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002715 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002716 sys.stdout.write(" cleanup: stopping server.\n")
2717 self.stop()
2718 if support.verbose:
2719 sys.stdout.write(" cleanup: joining server thread.\n")
2720 self.join()
2721 if support.verbose:
2722 sys.stdout.write(" cleanup: successfully joined.\n")
2723 # make sure that ConnectionHandler is removed from socket_map
2724 asyncore.close_all(ignore_all=True)
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01002725
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002726 def start (self, flag=None):
2727 self.flag = flag
2728 threading.Thread.start(self)
Antoine Pitrou2463e5f2013-03-28 22:24:43 +01002729
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002730 def run(self):
2731 self.active = True
2732 if self.flag:
2733 self.flag.set()
2734 while self.active:
Antoine Pitrou773b5db2010-04-27 08:53:36 +00002735 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002736 asyncore.loop(1)
2737 except:
2738 pass
Trent Nelson6b240cd2008-04-10 20:12:06 +00002739
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002740 def stop(self):
2741 self.active = False
2742 self.server.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00002743
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002744def server_params_test(client_context, server_context, indata=b"FOO\n",
2745 chatty=True, connectionchatty=False, sni_name=None,
2746 session=None):
2747 """
2748 Launch a server, connect a client to it and try various reads
2749 and writes.
2750 """
2751 stats = {}
2752 server = ThreadedEchoServer(context=server_context,
2753 chatty=chatty,
2754 connectionchatty=False)
2755 with server:
2756 with client_context.wrap_socket(socket.socket(),
2757 server_hostname=sni_name, session=session) as s:
2758 s.connect((HOST, server.port))
2759 for arg in [indata, bytearray(indata), memoryview(indata)]:
2760 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002761 if support.verbose:
Antoine Pitrou18c913e2010-04-27 10:59:39 +00002762 sys.stdout.write(
Antoine Pitrou480a1242010-04-28 21:37:09 +00002763 " client: sending %r...\n" % indata)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002764 s.write(arg)
Antoine Pitrou18c913e2010-04-27 10:59:39 +00002765 outdata = s.read()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002766 if connectionchatty:
2767 if support.verbose:
2768 sys.stdout.write(" client: read %r\n" % outdata)
Trent Nelson6b240cd2008-04-10 20:12:06 +00002769 if outdata != indata.lower():
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002770 raise AssertionError(
Antoine Pitrou480a1242010-04-28 21:37:09 +00002771 "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
2772 % (outdata[:20], len(outdata),
2773 indata[:20].lower(), len(indata)))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002774 s.write(b"over\n")
2775 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002776 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00002777 sys.stdout.write(" client: closing connection.\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002778 stats.update({
2779 'compression': s.compression(),
2780 'cipher': s.cipher(),
2781 'peercert': s.getpeercert(),
2782 'client_alpn_protocol': s.selected_alpn_protocol(),
2783 'client_npn_protocol': s.selected_npn_protocol(),
2784 'version': s.version(),
2785 'session_reused': s.session_reused,
2786 'session': s.session,
2787 })
2788 s.close()
2789 stats['server_alpn_protocols'] = server.selected_alpn_protocols
2790 stats['server_npn_protocols'] = server.selected_npn_protocols
2791 stats['server_shared_ciphers'] = server.shared_ciphers
2792 return stats
Trent Nelson6b240cd2008-04-10 20:12:06 +00002793
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002794def try_protocol_combo(server_protocol, client_protocol, expect_success,
2795 certsreqs=None, server_options=0, client_options=0):
2796 """
2797 Try to SSL-connect using *client_protocol* to *server_protocol*.
2798 If *expect_success* is true, assert that the connection succeeds,
2799 if it's false, assert that the connection fails.
2800 Also, if *expect_success* is a string, assert that it is the protocol
2801 version actually used by the connection.
2802 """
2803 if certsreqs is None:
2804 certsreqs = ssl.CERT_NONE
2805 certtype = {
2806 ssl.CERT_NONE: "CERT_NONE",
2807 ssl.CERT_OPTIONAL: "CERT_OPTIONAL",
2808 ssl.CERT_REQUIRED: "CERT_REQUIRED",
2809 }[certsreqs]
2810 if support.verbose:
2811 formatstr = (expect_success and " %s->%s %s\n") or " {%s->%s} %s\n"
2812 sys.stdout.write(formatstr %
2813 (ssl.get_protocol_name(client_protocol),
2814 ssl.get_protocol_name(server_protocol),
2815 certtype))
2816 client_context = ssl.SSLContext(client_protocol)
2817 client_context.options |= client_options
2818 server_context = ssl.SSLContext(server_protocol)
2819 server_context.options |= server_options
2820
Victor Stinner3ef63442019-02-19 18:06:03 +01002821 min_version = PROTOCOL_TO_TLS_VERSION.get(client_protocol, None)
2822 if (min_version is not None
2823 # SSLContext.minimum_version is only available on recent OpenSSL
2824 # (setter added in OpenSSL 1.1.0, getter added in OpenSSL 1.1.1)
2825 and hasattr(server_context, 'minimum_version')
2826 and server_protocol == ssl.PROTOCOL_TLS
2827 and server_context.minimum_version > min_version):
2828 # If OpenSSL configuration is strict and requires more recent TLS
2829 # version, we have to change the minimum to test old TLS versions.
2830 server_context.minimum_version = min_version
2831
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002832 # NOTE: we must enable "ALL" ciphers on the client, otherwise an
2833 # SSLv23 client will send an SSLv3 hello (rather than SSLv2)
2834 # starting from OpenSSL 1.0.0 (see issue #8322).
Christian Heimesa170fa12017-09-15 20:27:30 +02002835 if client_context.protocol == ssl.PROTOCOL_TLS:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002836 client_context.set_ciphers("ALL")
2837
Christian Heimesf6c6b582021-03-18 23:06:50 +01002838 seclevel_workaround(server_context, client_context)
2839
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002840 for ctx in (client_context, server_context):
2841 ctx.verify_mode = certsreqs
Christian Heimesbd5c7d22018-01-20 15:16:30 +01002842 ctx.load_cert_chain(SIGNED_CERTFILE)
2843 ctx.load_verify_locations(SIGNING_CA)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002844 try:
2845 stats = server_params_test(client_context, server_context,
2846 chatty=False, connectionchatty=False)
2847 # Protocol mismatch can result in either an SSLError, or a
2848 # "Connection reset by peer" error.
2849 except ssl.SSLError:
2850 if expect_success:
2851 raise
2852 except OSError as e:
2853 if expect_success or e.errno != errno.ECONNRESET:
2854 raise
2855 else:
2856 if not expect_success:
2857 raise AssertionError(
2858 "Client protocol %s succeeded with server protocol %s!"
2859 % (ssl.get_protocol_name(client_protocol),
2860 ssl.get_protocol_name(server_protocol)))
2861 elif (expect_success is not True
2862 and expect_success != stats['version']):
2863 raise AssertionError("version mismatch: expected %r, got %r"
2864 % (expect_success, stats['version']))
2865
2866
2867class ThreadedTests(unittest.TestCase):
2868
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002869 def test_echo(self):
2870 """Basic test of an SSL client connecting to a server"""
2871 if support.verbose:
2872 sys.stdout.write("\n")
2873 for protocol in PROTOCOLS:
2874 if protocol in {ssl.PROTOCOL_TLS_CLIENT, ssl.PROTOCOL_TLS_SERVER}:
2875 continue
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02002876 if not has_tls_protocol(protocol):
2877 continue
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002878 with self.subTest(protocol=ssl._PROTOCOL_NAMES[protocol]):
2879 context = ssl.SSLContext(protocol)
2880 context.load_cert_chain(CERTFILE)
Christian Heimesf6c6b582021-03-18 23:06:50 +01002881 seclevel_workaround(context)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002882 server_params_test(context, context,
2883 chatty=True, connectionchatty=True)
2884
Christian Heimesa170fa12017-09-15 20:27:30 +02002885 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002886
2887 with self.subTest(client=ssl.PROTOCOL_TLS_CLIENT, server=ssl.PROTOCOL_TLS_SERVER):
2888 server_params_test(client_context=client_context,
2889 server_context=server_context,
2890 chatty=True, connectionchatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02002891 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002892
2893 client_context.check_hostname = False
2894 with self.subTest(client=ssl.PROTOCOL_TLS_SERVER, server=ssl.PROTOCOL_TLS_CLIENT):
2895 with self.assertRaises(ssl.SSLError) as e:
2896 server_params_test(client_context=server_context,
2897 server_context=client_context,
2898 chatty=True, connectionchatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02002899 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002900 self.assertIn('called a function you should not call',
2901 str(e.exception))
2902
2903 with self.subTest(client=ssl.PROTOCOL_TLS_SERVER, server=ssl.PROTOCOL_TLS_SERVER):
2904 with self.assertRaises(ssl.SSLError) as e:
2905 server_params_test(client_context=server_context,
2906 server_context=server_context,
2907 chatty=True, connectionchatty=True)
2908 self.assertIn('called a function you should not call',
2909 str(e.exception))
2910
2911 with self.subTest(client=ssl.PROTOCOL_TLS_CLIENT, server=ssl.PROTOCOL_TLS_CLIENT):
2912 with self.assertRaises(ssl.SSLError) as e:
2913 server_params_test(client_context=server_context,
2914 server_context=client_context,
2915 chatty=True, connectionchatty=True)
2916 self.assertIn('called a function you should not call',
2917 str(e.exception))
2918
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002919 def test_getpeercert(self):
2920 if support.verbose:
2921 sys.stdout.write("\n")
Christian Heimesa170fa12017-09-15 20:27:30 +02002922
2923 client_context, server_context, hostname = testing_context()
2924 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002925 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002926 with client_context.wrap_socket(socket.socket(),
2927 do_handshake_on_connect=False,
2928 server_hostname=hostname) as s:
2929 s.connect((HOST, server.port))
2930 # getpeercert() raise ValueError while the handshake isn't
2931 # done.
2932 with self.assertRaises(ValueError):
2933 s.getpeercert()
2934 s.do_handshake()
2935 cert = s.getpeercert()
2936 self.assertTrue(cert, "Can't get peer certificate.")
2937 cipher = s.cipher()
2938 if support.verbose:
2939 sys.stdout.write(pprint.pformat(cert) + '\n')
2940 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
2941 if 'subject' not in cert:
2942 self.fail("No subject field in certificate: %s." %
2943 pprint.pformat(cert))
2944 if ((('organizationName', 'Python Software Foundation'),)
2945 not in cert['subject']):
2946 self.fail(
2947 "Missing or invalid 'organizationName' field in certificate subject; "
2948 "should be 'Python Software Foundation'.")
2949 self.assertIn('notBefore', cert)
2950 self.assertIn('notAfter', cert)
2951 before = ssl.cert_time_to_seconds(cert['notBefore'])
2952 after = ssl.cert_time_to_seconds(cert['notAfter'])
2953 self.assertLess(before, after)
Bill Janssen58afe4c2008-09-08 16:45:19 +00002954
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002955 @unittest.skipUnless(have_verify_flags(),
2956 "verify_flags need OpenSSL > 0.9.8")
2957 def test_crl_check(self):
2958 if support.verbose:
2959 sys.stdout.write("\n")
2960
Christian Heimesa170fa12017-09-15 20:27:30 +02002961 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002962
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002963 tf = getattr(ssl, "VERIFY_X509_TRUSTED_FIRST", 0)
Christian Heimesa170fa12017-09-15 20:27:30 +02002964 self.assertEqual(client_context.verify_flags, ssl.VERIFY_DEFAULT | tf)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002965
2966 # VERIFY_DEFAULT should pass
2967 server = ThreadedEchoServer(context=server_context, chatty=True)
2968 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002969 with client_context.wrap_socket(socket.socket(),
2970 server_hostname=hostname) as s:
Antoine Pitrou65a3f4b2011-12-21 16:52:40 +01002971 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002972 cert = s.getpeercert()
2973 self.assertTrue(cert, "Can't get peer certificate.")
Bill Janssen58afe4c2008-09-08 16:45:19 +00002974
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002975 # VERIFY_CRL_CHECK_LEAF without a loaded CRL file fails
Christian Heimesa170fa12017-09-15 20:27:30 +02002976 client_context.verify_flags |= ssl.VERIFY_CRL_CHECK_LEAF
Bill Janssen58afe4c2008-09-08 16:45:19 +00002977
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002978 server = ThreadedEchoServer(context=server_context, chatty=True)
2979 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002980 with client_context.wrap_socket(socket.socket(),
2981 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002982 with self.assertRaisesRegex(ssl.SSLError,
2983 "certificate verify failed"):
2984 s.connect((HOST, server.port))
Bill Janssen58afe4c2008-09-08 16:45:19 +00002985
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002986 # now load a CRL file. The CRL file is signed by the CA.
Christian Heimesa170fa12017-09-15 20:27:30 +02002987 client_context.load_verify_locations(CRLFILE)
Bill Janssen58afe4c2008-09-08 16:45:19 +00002988
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002989 server = ThreadedEchoServer(context=server_context, chatty=True)
2990 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02002991 with client_context.wrap_socket(socket.socket(),
2992 server_hostname=hostname) as s:
Antoine Pitroub4bebda2014-04-29 10:03:28 +02002993 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002994 cert = s.getpeercert()
2995 self.assertTrue(cert, "Can't get peer certificate.")
Antoine Pitroub4bebda2014-04-29 10:03:28 +02002996
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02002997 def test_check_hostname(self):
2998 if support.verbose:
2999 sys.stdout.write("\n")
Antoine Pitroub4bebda2014-04-29 10:03:28 +02003000
Christian Heimesa170fa12017-09-15 20:27:30 +02003001 client_context, server_context, hostname = testing_context()
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003002
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003003 # correct hostname should verify
3004 server = ThreadedEchoServer(context=server_context, chatty=True)
3005 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02003006 with client_context.wrap_socket(socket.socket(),
3007 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003008 s.connect((HOST, server.port))
3009 cert = s.getpeercert()
3010 self.assertTrue(cert, "Can't get peer certificate.")
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003011
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003012 # incorrect hostname should raise an exception
3013 server = ThreadedEchoServer(context=server_context, chatty=True)
3014 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02003015 with client_context.wrap_socket(socket.socket(),
3016 server_hostname="invalid") as s:
Christian Heimes61d478c2018-01-27 15:51:38 +01003017 with self.assertRaisesRegex(
3018 ssl.CertificateError,
3019 "Hostname mismatch, certificate is not valid for 'invalid'."):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003020 s.connect((HOST, server.port))
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003021
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003022 # missing server_hostname arg should cause an exception, too
3023 server = ThreadedEchoServer(context=server_context, chatty=True)
3024 with server:
3025 with socket.socket() as s:
3026 with self.assertRaisesRegex(ValueError,
3027 "check_hostname requires server_hostname"):
Christian Heimesa170fa12017-09-15 20:27:30 +02003028 client_context.wrap_socket(s)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003029
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003030 def test_ecc_cert(self):
3031 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3032 client_context.load_verify_locations(SIGNING_CA)
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003033 client_context.set_ciphers('ECDHE:ECDSA:!NULL:!aRSA')
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003034 hostname = SIGNED_CERTFILE_ECC_HOSTNAME
3035
3036 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3037 # load ECC cert
3038 server_context.load_cert_chain(SIGNED_CERTFILE_ECC)
3039
3040 # correct hostname should verify
3041 server = ThreadedEchoServer(context=server_context, chatty=True)
3042 with server:
3043 with client_context.wrap_socket(socket.socket(),
3044 server_hostname=hostname) as s:
3045 s.connect((HOST, server.port))
3046 cert = s.getpeercert()
3047 self.assertTrue(cert, "Can't get peer certificate.")
3048 cipher = s.cipher()[0].split('-')
3049 self.assertTrue(cipher[:2], ('ECDHE', 'ECDSA'))
3050
3051 def test_dual_rsa_ecc(self):
3052 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3053 client_context.load_verify_locations(SIGNING_CA)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003054 # TODO: fix TLSv1.3 once SSLContext can restrict signature
3055 # algorithms.
3056 client_context.options |= ssl.OP_NO_TLSv1_3
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003057 # only ECDSA certs
3058 client_context.set_ciphers('ECDHE:ECDSA:!NULL:!aRSA')
3059 hostname = SIGNED_CERTFILE_ECC_HOSTNAME
3060
3061 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3062 # load ECC and RSA key/cert pairs
3063 server_context.load_cert_chain(SIGNED_CERTFILE_ECC)
3064 server_context.load_cert_chain(SIGNED_CERTFILE)
3065
3066 # correct hostname should verify
3067 server = ThreadedEchoServer(context=server_context, chatty=True)
3068 with server:
3069 with client_context.wrap_socket(socket.socket(),
3070 server_hostname=hostname) as s:
3071 s.connect((HOST, server.port))
3072 cert = s.getpeercert()
3073 self.assertTrue(cert, "Can't get peer certificate.")
3074 cipher = s.cipher()[0].split('-')
3075 self.assertTrue(cipher[:2], ('ECDHE', 'ECDSA'))
3076
Christian Heimes66e57422018-01-29 14:25:13 +01003077 def test_check_hostname_idn(self):
3078 if support.verbose:
3079 sys.stdout.write("\n")
3080
Christian Heimes11a14932018-02-24 02:35:08 +01003081 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Christian Heimes66e57422018-01-29 14:25:13 +01003082 server_context.load_cert_chain(IDNSANSFILE)
3083
Christian Heimes11a14932018-02-24 02:35:08 +01003084 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Christian Heimes66e57422018-01-29 14:25:13 +01003085 context.verify_mode = ssl.CERT_REQUIRED
3086 context.check_hostname = True
3087 context.load_verify_locations(SIGNING_CA)
3088
3089 # correct hostname should verify, when specified in several
3090 # different ways
3091 idn_hostnames = [
3092 ('könig.idn.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003093 'xn--knig-5qa.idn.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003094 ('xn--knig-5qa.idn.pythontest.net',
3095 'xn--knig-5qa.idn.pythontest.net'),
3096 (b'xn--knig-5qa.idn.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003097 'xn--knig-5qa.idn.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003098
3099 ('königsgäßchen.idna2003.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003100 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
Christian Heimes66e57422018-01-29 14:25:13 +01003101 ('xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
3102 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
3103 (b'xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
Christian Heimes11a14932018-02-24 02:35:08 +01003104 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
3105
3106 # ('königsgäßchen.idna2008.pythontest.net',
3107 # 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3108 ('xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
3109 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3110 (b'xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
3111 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
3112
Christian Heimes66e57422018-01-29 14:25:13 +01003113 ]
3114 for server_hostname, expected_hostname in idn_hostnames:
3115 server = ThreadedEchoServer(context=server_context, chatty=True)
3116 with server:
3117 with context.wrap_socket(socket.socket(),
3118 server_hostname=server_hostname) as s:
3119 self.assertEqual(s.server_hostname, expected_hostname)
3120 s.connect((HOST, server.port))
3121 cert = s.getpeercert()
3122 self.assertEqual(s.server_hostname, expected_hostname)
3123 self.assertTrue(cert, "Can't get peer certificate.")
3124
Christian Heimes66e57422018-01-29 14:25:13 +01003125 # incorrect hostname should raise an exception
3126 server = ThreadedEchoServer(context=server_context, chatty=True)
3127 with server:
3128 with context.wrap_socket(socket.socket(),
3129 server_hostname="python.example.org") as s:
3130 with self.assertRaises(ssl.CertificateError):
3131 s.connect((HOST, server.port))
3132
Christian Heimes529525f2018-05-23 22:24:45 +02003133 def test_wrong_cert_tls12(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003134 """Connecting when the server rejects the client's certificate
3135
3136 Launch a server with CERT_REQUIRED, and check that trying to
3137 connect to it with a wrong client certificate fails.
3138 """
Christian Heimes05d9fe32018-02-27 08:55:39 +01003139 client_context, server_context, hostname = testing_context()
Christian Heimes88bfd0b2018-08-14 12:54:19 +02003140 # load client cert that is not signed by trusted CA
3141 client_context.load_cert_chain(CERTFILE)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003142 # require TLS client authentication
3143 server_context.verify_mode = ssl.CERT_REQUIRED
Christian Heimes529525f2018-05-23 22:24:45 +02003144 # TLS 1.3 has different handshake
3145 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimes05d9fe32018-02-27 08:55:39 +01003146
3147 server = ThreadedEchoServer(
3148 context=server_context, chatty=True, connectionchatty=True,
3149 )
3150
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003151 with server, \
Christian Heimes05d9fe32018-02-27 08:55:39 +01003152 client_context.wrap_socket(socket.socket(),
3153 server_hostname=hostname) as s:
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003154 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003155 # Expect either an SSL error about the server rejecting
3156 # the connection, or a low-level connection reset (which
3157 # sometimes happens on Windows)
3158 s.connect((HOST, server.port))
3159 except ssl.SSLError as e:
3160 if support.verbose:
3161 sys.stdout.write("\nSSLError is %r\n" % e)
3162 except OSError as e:
3163 if e.errno != errno.ECONNRESET:
3164 raise
3165 if support.verbose:
3166 sys.stdout.write("\nsocket.error is %r\n" % e)
3167 else:
3168 self.fail("Use of invalid cert should have failed!")
3169
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003170 @requires_tls_version('TLSv1_3')
Christian Heimes529525f2018-05-23 22:24:45 +02003171 def test_wrong_cert_tls13(self):
3172 client_context, server_context, hostname = testing_context()
Christian Heimes88bfd0b2018-08-14 12:54:19 +02003173 # load client cert that is not signed by trusted CA
3174 client_context.load_cert_chain(CERTFILE)
Christian Heimes529525f2018-05-23 22:24:45 +02003175 server_context.verify_mode = ssl.CERT_REQUIRED
3176 server_context.minimum_version = ssl.TLSVersion.TLSv1_3
3177 client_context.minimum_version = ssl.TLSVersion.TLSv1_3
3178
3179 server = ThreadedEchoServer(
3180 context=server_context, chatty=True, connectionchatty=True,
3181 )
3182 with server, \
3183 client_context.wrap_socket(socket.socket(),
3184 server_hostname=hostname) as s:
3185 # TLS 1.3 perform client cert exchange after handshake
3186 s.connect((HOST, server.port))
3187 try:
3188 s.write(b'data')
3189 s.read(4)
3190 except ssl.SSLError as e:
3191 if support.verbose:
3192 sys.stdout.write("\nSSLError is %r\n" % e)
3193 except OSError as e:
3194 if e.errno != errno.ECONNRESET:
3195 raise
3196 if support.verbose:
3197 sys.stdout.write("\nsocket.error is %r\n" % e)
3198 else:
3199 self.fail("Use of invalid cert should have failed!")
3200
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003201 def test_rude_shutdown(self):
3202 """A brutal shutdown of an SSL server should raise an OSError
3203 in the client when attempting handshake.
3204 """
3205 listener_ready = threading.Event()
3206 listener_gone = threading.Event()
3207
3208 s = socket.socket()
Serhiy Storchaka16994912020-04-25 10:06:29 +03003209 port = socket_helper.bind_port(s, HOST)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003210
3211 # `listener` runs in a thread. It sits in an accept() until
3212 # the main thread connects. Then it rudely closes the socket,
3213 # and sets Event `listener_gone` to let the main thread know
3214 # the socket is gone.
3215 def listener():
3216 s.listen()
3217 listener_ready.set()
3218 newsock, addr = s.accept()
3219 newsock.close()
3220 s.close()
3221 listener_gone.set()
3222
3223 def connector():
3224 listener_ready.wait()
3225 with socket.socket() as c:
3226 c.connect((HOST, port))
3227 listener_gone.wait()
Antoine Pitrou40f08742010-04-24 22:04:40 +00003228 try:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003229 ssl_sock = test_wrap_socket(c)
3230 except OSError:
3231 pass
3232 else:
3233 self.fail('connecting to closed SSL socket should have failed')
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00003234
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003235 t = threading.Thread(target=listener)
3236 t.start()
3237 try:
3238 connector()
3239 finally:
Antoine Pitrou5c89b4e2012-11-11 01:25:36 +01003240 t.join()
Antoine Pitrou5c89b4e2012-11-11 01:25:36 +01003241
Christian Heimesb3ad0e52017-09-08 12:00:19 -07003242 def test_ssl_cert_verify_error(self):
3243 if support.verbose:
3244 sys.stdout.write("\n")
3245
3246 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
3247 server_context.load_cert_chain(SIGNED_CERTFILE)
3248
3249 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3250
3251 server = ThreadedEchoServer(context=server_context, chatty=True)
3252 with server:
3253 with context.wrap_socket(socket.socket(),
Christian Heimesa170fa12017-09-15 20:27:30 +02003254 server_hostname=SIGNED_CERTFILE_HOSTNAME) as s:
Christian Heimesb3ad0e52017-09-08 12:00:19 -07003255 try:
3256 s.connect((HOST, server.port))
3257 except ssl.SSLError as e:
3258 msg = 'unable to get local issuer certificate'
3259 self.assertIsInstance(e, ssl.SSLCertVerificationError)
3260 self.assertEqual(e.verify_code, 20)
3261 self.assertEqual(e.verify_message, msg)
3262 self.assertIn(msg, repr(e))
3263 self.assertIn('certificate verify failed', repr(e))
3264
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003265 @requires_tls_version('SSLv2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003266 def test_protocol_sslv2(self):
3267 """Connecting to an SSLv2 server with various client options"""
3268 if support.verbose:
3269 sys.stdout.write("\n")
3270 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
3271 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
3272 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
Christian Heimesa170fa12017-09-15 20:27:30 +02003273 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003274 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003275 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
3276 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
3277 # SSLv23 client with specific SSL options
3278 if no_sslv2_implies_sslv3_hello():
3279 # No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs
Christian Heimesa170fa12017-09-15 20:27:30 +02003280 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003281 client_options=ssl.OP_NO_SSLv2)
Christian Heimesa170fa12017-09-15 20:27:30 +02003282 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003283 client_options=ssl.OP_NO_SSLv3)
Christian Heimesa170fa12017-09-15 20:27:30 +02003284 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003285 client_options=ssl.OP_NO_TLSv1)
Antoine Pitrou242db722013-05-01 20:52:07 +02003286
Christian Heimesa170fa12017-09-15 20:27:30 +02003287 def test_PROTOCOL_TLS(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003288 """Connecting to an SSLv23 server with various client options"""
3289 if support.verbose:
3290 sys.stdout.write("\n")
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003291 if has_tls_version('SSLv2'):
Antoine Pitrou8f85f902012-01-03 22:46:48 +01003292 try:
Christian Heimesa170fa12017-09-15 20:27:30 +02003293 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv2, True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003294 except OSError as x:
3295 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
3296 if support.verbose:
3297 sys.stdout.write(
3298 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
3299 % str(x))
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003300 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003301 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False)
3302 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003303 if has_tls_version('TLSv1'):
3304 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1')
Antoine Pitrou8f85f902012-01-03 22:46:48 +01003305
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003306 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003307 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False, ssl.CERT_OPTIONAL)
3308 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True, ssl.CERT_OPTIONAL)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003309 if has_tls_version('TLSv1'):
3310 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003311
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003312 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003313 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False, ssl.CERT_REQUIRED)
3314 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True, ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003315 if has_tls_version('TLSv1'):
3316 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003317
3318 # Server with specific SSL options
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003319 if has_tls_version('SSLv3'):
Christian Heimesa170fa12017-09-15 20:27:30 +02003320 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv3, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003321 server_options=ssl.OP_NO_SSLv3)
3322 # Will choose TLSv1
Christian Heimesa170fa12017-09-15 20:27:30 +02003323 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS, True,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003324 server_options=ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003325 if has_tls_version('TLSv1'):
3326 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1, False,
3327 server_options=ssl.OP_NO_TLSv1)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003328
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003329 @requires_tls_version('SSLv3')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003330 def test_protocol_sslv3(self):
3331 """Connecting to an SSLv3 server with various client options"""
3332 if support.verbose:
3333 sys.stdout.write("\n")
3334 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3')
3335 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_OPTIONAL)
3336 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003337 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003338 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003339 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003340 client_options=ssl.OP_NO_SSLv3)
3341 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
3342 if no_sslv2_implies_sslv3_hello():
3343 # No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs
Christian Heimesa170fa12017-09-15 20:27:30 +02003344 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLS,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003345 False, client_options=ssl.OP_NO_SSLv2)
3346
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003347 @requires_tls_version('TLSv1')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003348 def test_protocol_tlsv1(self):
3349 """Connecting to a TLSv1 server with various client options"""
3350 if support.verbose:
3351 sys.stdout.write("\n")
3352 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1')
3353 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL)
3354 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003355 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003356 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003357 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003358 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003359 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003360 client_options=ssl.OP_NO_TLSv1)
3361
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003362 @requires_tls_version('TLSv1_1')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003363 def test_protocol_tlsv1_1(self):
3364 """Connecting to a TLSv1.1 server with various client options.
3365 Testing against older TLS versions."""
3366 if support.verbose:
3367 sys.stdout.write("\n")
3368 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1')
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003369 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003370 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003371 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003372 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003373 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003374 client_options=ssl.OP_NO_TLSv1_1)
3375
Christian Heimesa170fa12017-09-15 20:27:30 +02003376 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1')
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003377 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False)
3378 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003379
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003380 @requires_tls_version('TLSv1_2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003381 def test_protocol_tlsv1_2(self):
3382 """Connecting to a TLSv1.2 server with various client options.
3383 Testing against older TLS versions."""
3384 if support.verbose:
3385 sys.stdout.write("\n")
3386 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2',
3387 server_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,
3388 client_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003389 if has_tls_version('SSLv2'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003390 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv2, False)
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003391 if has_tls_version('SSLv3'):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003392 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv3, False)
Christian Heimesa170fa12017-09-15 20:27:30 +02003393 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLS, False,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003394 client_options=ssl.OP_NO_TLSv1_2)
3395
Christian Heimesa170fa12017-09-15 20:27:30 +02003396 try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003397 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1, False)
3398 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_2, False)
3399 try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False)
3400 try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False)
3401
3402 def test_starttls(self):
3403 """Switching from clear text to encrypted and back again."""
3404 msgs = (b"msg 1", b"MSG 2", b"STARTTLS", b"MSG 3", b"msg 4", b"ENDTLS", b"msg 5", b"msg 6")
3405
3406 server = ThreadedEchoServer(CERTFILE,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003407 starttls_server=True,
3408 chatty=True,
3409 connectionchatty=True)
3410 wrapped = False
3411 with server:
3412 s = socket.socket()
Serhiy Storchaka5eca7f32019-09-01 12:12:52 +03003413 s.setblocking(True)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003414 s.connect((HOST, server.port))
Antoine Pitroud6494802011-07-21 01:11:30 +02003415 if support.verbose:
3416 sys.stdout.write("\n")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003417 for indata in msgs:
Antoine Pitroud6494802011-07-21 01:11:30 +02003418 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003419 sys.stdout.write(
3420 " client: sending %r...\n" % indata)
3421 if wrapped:
3422 conn.write(indata)
3423 outdata = conn.read()
3424 else:
3425 s.send(indata)
3426 outdata = s.recv(1024)
3427 msg = outdata.strip().lower()
3428 if indata == b"STARTTLS" and msg.startswith(b"ok"):
3429 # STARTTLS ok, switch to secure mode
3430 if support.verbose:
3431 sys.stdout.write(
3432 " client: read %r from server, starting TLS...\n"
3433 % msg)
Christian Heimesa170fa12017-09-15 20:27:30 +02003434 conn = test_wrap_socket(s)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003435 wrapped = True
3436 elif indata == b"ENDTLS" and msg.startswith(b"ok"):
3437 # ENDTLS ok, switch back to clear text
3438 if support.verbose:
3439 sys.stdout.write(
3440 " client: read %r from server, ending TLS...\n"
3441 % msg)
3442 s = conn.unwrap()
3443 wrapped = False
3444 else:
3445 if support.verbose:
3446 sys.stdout.write(
3447 " client: read %r from server\n" % msg)
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003448 if support.verbose:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003449 sys.stdout.write(" client: closing connection.\n")
3450 if wrapped:
3451 conn.write(b"over\n")
3452 else:
3453 s.send(b"over\n")
3454 if wrapped:
3455 conn.close()
3456 else:
3457 s.close()
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003458
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003459 def test_socketserver(self):
3460 """Using socketserver to create and manage SSL connections."""
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003461 server = make_https_server(self, certfile=SIGNED_CERTFILE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003462 # try to connect
3463 if support.verbose:
3464 sys.stdout.write('\n')
3465 with open(CERTFILE, 'rb') as f:
3466 d1 = f.read()
3467 d2 = ''
3468 # now fetch the same data from the HTTPS server
3469 url = 'https://localhost:%d/%s' % (
3470 server.port, os.path.split(CERTFILE)[1])
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003471 context = ssl.create_default_context(cafile=SIGNING_CA)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003472 f = urllib.request.urlopen(url, context=context)
3473 try:
3474 dlen = f.info().get("content-length")
3475 if dlen and (int(dlen) > 0):
3476 d2 = f.read(int(dlen))
3477 if support.verbose:
3478 sys.stdout.write(
3479 " client: read %d bytes from remote server '%s'\n"
3480 % (len(d2), server))
3481 finally:
3482 f.close()
3483 self.assertEqual(d1, d2)
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01003484
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003485 def test_asyncore_server(self):
3486 """Check the example asyncore integration."""
3487 if support.verbose:
3488 sys.stdout.write("\n")
Antoine Pitrou0e576f12011-12-22 10:03:38 +01003489
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003490 indata = b"FOO\n"
3491 server = AsyncoreEchoServer(CERTFILE)
3492 with server:
3493 s = test_wrap_socket(socket.socket())
3494 s.connect(('127.0.0.1', server.port))
3495 if support.verbose:
3496 sys.stdout.write(
3497 " client: sending %r...\n" % indata)
3498 s.write(indata)
3499 outdata = s.read()
3500 if support.verbose:
3501 sys.stdout.write(" client: read %r\n" % outdata)
3502 if outdata != indata.lower():
3503 self.fail(
3504 "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
3505 % (outdata[:20], len(outdata),
3506 indata[:20].lower(), len(indata)))
3507 s.write(b"over\n")
3508 if support.verbose:
3509 sys.stdout.write(" client: closing connection.\n")
3510 s.close()
3511 if support.verbose:
3512 sys.stdout.write(" client: connection closed.\n")
Benjamin Petersoncca27322015-01-23 16:35:37 -05003513
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003514 def test_recv_send(self):
3515 """Test recv(), send() and friends."""
3516 if support.verbose:
3517 sys.stdout.write("\n")
3518
3519 server = ThreadedEchoServer(CERTFILE,
3520 certreqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003521 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003522 cacerts=CERTFILE,
3523 chatty=True,
3524 connectionchatty=False)
3525 with server:
3526 s = test_wrap_socket(socket.socket(),
3527 server_side=False,
3528 certfile=CERTFILE,
3529 ca_certs=CERTFILE,
3530 cert_reqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003531 ssl_version=ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003532 s.connect((HOST, server.port))
3533 # helper methods for standardising recv* method signatures
3534 def _recv_into():
3535 b = bytearray(b"\0"*100)
3536 count = s.recv_into(b)
3537 return b[:count]
3538
3539 def _recvfrom_into():
3540 b = bytearray(b"\0"*100)
3541 count, addr = s.recvfrom_into(b)
3542 return b[:count]
3543
3544 # (name, method, expect success?, *args, return value func)
3545 send_methods = [
3546 ('send', s.send, True, [], len),
3547 ('sendto', s.sendto, False, ["some.address"], len),
3548 ('sendall', s.sendall, True, [], lambda x: None),
3549 ]
3550 # (name, method, whether to expect success, *args)
3551 recv_methods = [
3552 ('recv', s.recv, True, []),
3553 ('recvfrom', s.recvfrom, False, ["some.address"]),
3554 ('recv_into', _recv_into, True, []),
3555 ('recvfrom_into', _recvfrom_into, False, []),
3556 ]
3557 data_prefix = "PREFIX_"
3558
3559 for (meth_name, send_meth, expect_success, args,
3560 ret_val_meth) in send_methods:
3561 indata = (data_prefix + meth_name).encode('ascii')
3562 try:
3563 ret = send_meth(indata, *args)
3564 msg = "sending with {}".format(meth_name)
3565 self.assertEqual(ret, ret_val_meth(indata), msg=msg)
3566 outdata = s.read()
3567 if outdata != indata.lower():
3568 self.fail(
3569 "While sending with <<{name:s}>> bad data "
3570 "<<{outdata:r}>> ({nout:d}) received; "
3571 "expected <<{indata:r}>> ({nin:d})\n".format(
3572 name=meth_name, outdata=outdata[:20],
3573 nout=len(outdata),
3574 indata=indata[:20], nin=len(indata)
3575 )
3576 )
3577 except ValueError as e:
3578 if expect_success:
3579 self.fail(
3580 "Failed to send with method <<{name:s}>>; "
3581 "expected to succeed.\n".format(name=meth_name)
3582 )
3583 if not str(e).startswith(meth_name):
3584 self.fail(
3585 "Method <<{name:s}>> failed with unexpected "
3586 "exception message: {exp:s}\n".format(
3587 name=meth_name, exp=e
3588 )
3589 )
3590
3591 for meth_name, recv_meth, expect_success, args in recv_methods:
3592 indata = (data_prefix + meth_name).encode('ascii')
3593 try:
3594 s.send(indata)
3595 outdata = recv_meth(*args)
3596 if outdata != indata.lower():
3597 self.fail(
3598 "While receiving with <<{name:s}>> bad data "
3599 "<<{outdata:r}>> ({nout:d}) received; "
3600 "expected <<{indata:r}>> ({nin:d})\n".format(
3601 name=meth_name, outdata=outdata[:20],
3602 nout=len(outdata),
3603 indata=indata[:20], nin=len(indata)
3604 )
3605 )
3606 except ValueError as e:
3607 if expect_success:
3608 self.fail(
3609 "Failed to receive with method <<{name:s}>>; "
3610 "expected to succeed.\n".format(name=meth_name)
3611 )
3612 if not str(e).startswith(meth_name):
3613 self.fail(
3614 "Method <<{name:s}>> failed with unexpected "
3615 "exception message: {exp:s}\n".format(
3616 name=meth_name, exp=e
3617 )
3618 )
3619 # consume data
3620 s.read()
3621
3622 # read(-1, buffer) is supported, even though read(-1) is not
3623 data = b"data"
3624 s.send(data)
3625 buffer = bytearray(len(data))
3626 self.assertEqual(s.read(-1, buffer), len(data))
3627 self.assertEqual(buffer, data)
3628
Christian Heimes888bbdc2017-09-07 14:18:21 -07003629 # sendall accepts bytes-like objects
3630 if ctypes is not None:
3631 ubyte = ctypes.c_ubyte * len(data)
3632 byteslike = ubyte.from_buffer_copy(data)
3633 s.sendall(byteslike)
3634 self.assertEqual(s.read(), data)
3635
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003636 # Make sure sendmsg et al are disallowed to avoid
3637 # inadvertent disclosure of data and/or corruption
3638 # of the encrypted data stream
Serhiy Storchaka42b1d612018-12-06 22:36:55 +02003639 self.assertRaises(NotImplementedError, s.dup)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003640 self.assertRaises(NotImplementedError, s.sendmsg, [b"data"])
3641 self.assertRaises(NotImplementedError, s.recvmsg, 100)
3642 self.assertRaises(NotImplementedError,
Serhiy Storchaka42b1d612018-12-06 22:36:55 +02003643 s.recvmsg_into, [bytearray(100)])
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003644 s.write(b"over\n")
3645
3646 self.assertRaises(ValueError, s.recv, -1)
3647 self.assertRaises(ValueError, s.read, -1)
3648
3649 s.close()
3650
3651 def test_recv_zero(self):
3652 server = ThreadedEchoServer(CERTFILE)
3653 server.__enter__()
3654 self.addCleanup(server.__exit__, None, None)
3655 s = socket.create_connection((HOST, server.port))
3656 self.addCleanup(s.close)
3657 s = test_wrap_socket(s, suppress_ragged_eofs=False)
3658 self.addCleanup(s.close)
3659
3660 # recv/read(0) should return no data
3661 s.send(b"data")
3662 self.assertEqual(s.recv(0), b"")
3663 self.assertEqual(s.read(0), b"")
3664 self.assertEqual(s.read(), b"data")
3665
3666 # Should not block if the other end sends no data
3667 s.setblocking(False)
3668 self.assertEqual(s.recv(0), b"")
3669 self.assertEqual(s.recv_into(bytearray()), 0)
3670
3671 def test_nonblocking_send(self):
3672 server = ThreadedEchoServer(CERTFILE,
3673 certreqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003674 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003675 cacerts=CERTFILE,
3676 chatty=True,
3677 connectionchatty=False)
3678 with server:
3679 s = test_wrap_socket(socket.socket(),
3680 server_side=False,
3681 certfile=CERTFILE,
3682 ca_certs=CERTFILE,
3683 cert_reqs=ssl.CERT_NONE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003684 ssl_version=ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003685 s.connect((HOST, server.port))
3686 s.setblocking(False)
3687
3688 # If we keep sending data, at some point the buffers
3689 # will be full and the call will block
3690 buf = bytearray(8192)
3691 def fill_buffer():
3692 while True:
3693 s.send(buf)
3694 self.assertRaises((ssl.SSLWantWriteError,
3695 ssl.SSLWantReadError), fill_buffer)
3696
3697 # Now read all the output and discard it
3698 s.setblocking(True)
3699 s.close()
3700
3701 def test_handshake_timeout(self):
3702 # Issue #5103: SSL handshake must respect the socket timeout
3703 server = socket.socket(socket.AF_INET)
3704 host = "127.0.0.1"
Serhiy Storchaka16994912020-04-25 10:06:29 +03003705 port = socket_helper.bind_port(server)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003706 started = threading.Event()
3707 finish = False
3708
3709 def serve():
3710 server.listen()
3711 started.set()
3712 conns = []
3713 while not finish:
3714 r, w, e = select.select([server], [], [], 0.1)
3715 if server in r:
3716 # Let the socket hang around rather than having
3717 # it closed by garbage collection.
3718 conns.append(server.accept()[0])
3719 for sock in conns:
3720 sock.close()
3721
3722 t = threading.Thread(target=serve)
3723 t.start()
3724 started.wait()
3725
3726 try:
3727 try:
3728 c = socket.socket(socket.AF_INET)
3729 c.settimeout(0.2)
3730 c.connect((host, port))
3731 # Will attempt handshake and time out
Christian Heimes03c8ddd2020-11-20 09:26:07 +01003732 self.assertRaisesRegex(TimeoutError, "timed out",
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003733 test_wrap_socket, c)
3734 finally:
3735 c.close()
3736 try:
3737 c = socket.socket(socket.AF_INET)
3738 c = test_wrap_socket(c)
3739 c.settimeout(0.2)
3740 # Will attempt handshake and time out
Christian Heimes03c8ddd2020-11-20 09:26:07 +01003741 self.assertRaisesRegex(TimeoutError, "timed out",
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003742 c.connect, (host, port))
3743 finally:
3744 c.close()
3745 finally:
3746 finish = True
3747 t.join()
3748 server.close()
3749
3750 def test_server_accept(self):
3751 # Issue #16357: accept() on a SSLSocket created through
3752 # SSLContext.wrap_socket().
Christian Heimesa170fa12017-09-15 20:27:30 +02003753 context = ssl.SSLContext(ssl.PROTOCOL_TLS)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003754 context.verify_mode = ssl.CERT_REQUIRED
Christian Heimesbd5c7d22018-01-20 15:16:30 +01003755 context.load_verify_locations(SIGNING_CA)
3756 context.load_cert_chain(SIGNED_CERTFILE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003757 server = socket.socket(socket.AF_INET)
3758 host = "127.0.0.1"
Serhiy Storchaka16994912020-04-25 10:06:29 +03003759 port = socket_helper.bind_port(server)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003760 server = context.wrap_socket(server, server_side=True)
3761 self.assertTrue(server.server_side)
3762
3763 evt = threading.Event()
3764 remote = None
3765 peer = None
3766 def serve():
3767 nonlocal remote, peer
3768 server.listen()
3769 # Block on the accept and wait on the connection to close.
3770 evt.set()
3771 remote, peer = server.accept()
Christian Heimes529525f2018-05-23 22:24:45 +02003772 remote.send(remote.recv(4))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003773
3774 t = threading.Thread(target=serve)
3775 t.start()
3776 # Client wait until server setup and perform a connect.
3777 evt.wait()
3778 client = context.wrap_socket(socket.socket())
3779 client.connect((host, port))
Christian Heimes529525f2018-05-23 22:24:45 +02003780 client.send(b'data')
3781 client.recv()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003782 client_addr = client.getsockname()
3783 client.close()
3784 t.join()
3785 remote.close()
3786 server.close()
3787 # Sanity checks.
3788 self.assertIsInstance(remote, ssl.SSLSocket)
3789 self.assertEqual(peer, client_addr)
3790
3791 def test_getpeercert_enotconn(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02003792 context = ssl.SSLContext(ssl.PROTOCOL_TLS)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003793 with context.wrap_socket(socket.socket()) as sock:
3794 with self.assertRaises(OSError) as cm:
3795 sock.getpeercert()
3796 self.assertEqual(cm.exception.errno, errno.ENOTCONN)
3797
3798 def test_do_handshake_enotconn(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02003799 context = ssl.SSLContext(ssl.PROTOCOL_TLS)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003800 with context.wrap_socket(socket.socket()) as sock:
3801 with self.assertRaises(OSError) as cm:
3802 sock.do_handshake()
3803 self.assertEqual(cm.exception.errno, errno.ENOTCONN)
3804
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003805 def test_no_shared_ciphers(self):
3806 client_context, server_context, hostname = testing_context()
3807 # OpenSSL enables all TLS 1.3 ciphers, enforce TLS 1.2 for test
3808 client_context.options |= ssl.OP_NO_TLSv1_3
Victor Stinner5e922652018-09-07 17:30:33 +02003809 # Force different suites on client and server
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003810 client_context.set_ciphers("AES128")
3811 server_context.set_ciphers("AES256")
3812 with ThreadedEchoServer(context=server_context) as server:
3813 with client_context.wrap_socket(socket.socket(),
3814 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003815 with self.assertRaises(OSError):
3816 s.connect((HOST, server.port))
3817 self.assertIn("no shared cipher", server.conn_errors[0])
3818
3819 def test_version_basic(self):
3820 """
3821 Basic tests for SSLSocket.version().
3822 More tests are done in the test_protocol_*() methods.
3823 """
Christian Heimesa170fa12017-09-15 20:27:30 +02003824 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3825 context.check_hostname = False
3826 context.verify_mode = ssl.CERT_NONE
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003827 with ThreadedEchoServer(CERTFILE,
Christian Heimesa170fa12017-09-15 20:27:30 +02003828 ssl_version=ssl.PROTOCOL_TLS_SERVER,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003829 chatty=False) as server:
3830 with context.wrap_socket(socket.socket()) as s:
3831 self.assertIs(s.version(), None)
Christian Heimes141c5e82018-02-24 21:10:57 +01003832 self.assertIs(s._sslobj, None)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003833 s.connect((HOST, server.port))
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003834 if IS_OPENSSL_1_1_1 and has_tls_version('TLSv1_3'):
Christian Heimes05d9fe32018-02-27 08:55:39 +01003835 self.assertEqual(s.version(), 'TLSv1.3')
3836 elif ssl.OPENSSL_VERSION_INFO >= (1, 0, 2):
Christian Heimesa170fa12017-09-15 20:27:30 +02003837 self.assertEqual(s.version(), 'TLSv1.2')
3838 else: # 0.9.8 to 1.0.1
3839 self.assertIn(s.version(), ('TLSv1', 'TLSv1.2'))
Christian Heimes141c5e82018-02-24 21:10:57 +01003840 self.assertIs(s._sslobj, None)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003841 self.assertIs(s.version(), None)
3842
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003843 @requires_tls_version('TLSv1_3')
Christian Heimescb5b68a2017-09-07 18:07:00 -07003844 def test_tls1_3(self):
3845 context = ssl.SSLContext(ssl.PROTOCOL_TLS)
3846 context.load_cert_chain(CERTFILE)
Christian Heimescb5b68a2017-09-07 18:07:00 -07003847 context.options |= (
3848 ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_TLSv1_2
3849 )
3850 with ThreadedEchoServer(context=context) as server:
3851 with context.wrap_socket(socket.socket()) as s:
3852 s.connect((HOST, server.port))
Christian Heimes05d9fe32018-02-27 08:55:39 +01003853 self.assertIn(s.cipher()[0], {
Christian Heimese8eb6cb2018-05-22 22:50:12 +02003854 'TLS_AES_256_GCM_SHA384',
3855 'TLS_CHACHA20_POLY1305_SHA256',
3856 'TLS_AES_128_GCM_SHA256',
Christian Heimes05d9fe32018-02-27 08:55:39 +01003857 })
3858 self.assertEqual(s.version(), 'TLSv1.3')
Christian Heimescb5b68a2017-09-07 18:07:00 -07003859
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003860 @requires_minimum_version
3861 @requires_tls_version('TLSv1_2')
3862 def test_min_max_version_tlsv1_2(self):
Christian Heimes698dde12018-02-27 11:54:43 +01003863 client_context, server_context, hostname = testing_context()
3864 # client TLSv1.0 to 1.2
3865 client_context.minimum_version = ssl.TLSVersion.TLSv1
3866 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
3867 # server only TLSv1.2
3868 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
3869 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
3870
3871 with ThreadedEchoServer(context=server_context) as server:
3872 with client_context.wrap_socket(socket.socket(),
3873 server_hostname=hostname) as s:
3874 s.connect((HOST, server.port))
3875 self.assertEqual(s.version(), 'TLSv1.2')
3876
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003877 @requires_minimum_version
3878 @requires_tls_version('TLSv1_1')
3879 def test_min_max_version_tlsv1_1(self):
3880 client_context, server_context, hostname = testing_context()
Christian Heimes698dde12018-02-27 11:54:43 +01003881 # client 1.0 to 1.2, server 1.0 to 1.1
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003882 client_context.minimum_version = ssl.TLSVersion.TLSv1
3883 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimes698dde12018-02-27 11:54:43 +01003884 server_context.minimum_version = ssl.TLSVersion.TLSv1
3885 server_context.maximum_version = ssl.TLSVersion.TLSv1_1
Christian Heimesf6c6b582021-03-18 23:06:50 +01003886 seclevel_workaround(client_context, server_context)
Christian Heimes698dde12018-02-27 11:54:43 +01003887
3888 with ThreadedEchoServer(context=server_context) as server:
3889 with client_context.wrap_socket(socket.socket(),
3890 server_hostname=hostname) as s:
3891 s.connect((HOST, server.port))
3892 self.assertEqual(s.version(), 'TLSv1.1')
3893
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003894 @requires_minimum_version
3895 @requires_tls_version('TLSv1_2')
Christian Heimesce04e712020-11-18 13:10:53 +01003896 @requires_tls_version('TLSv1')
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003897 def test_min_max_version_mismatch(self):
3898 client_context, server_context, hostname = testing_context()
Christian Heimes698dde12018-02-27 11:54:43 +01003899 # client 1.0, server 1.2 (mismatch)
Christian Heimes698dde12018-02-27 11:54:43 +01003900 server_context.maximum_version = ssl.TLSVersion.TLSv1_2
Christian Heimesc9bc49c2019-09-11 19:24:47 +02003901 server_context.minimum_version = ssl.TLSVersion.TLSv1_2
Christian Heimese35d1ba2019-06-03 20:40:15 +02003902 client_context.maximum_version = ssl.TLSVersion.TLSv1
Christian Heimesde606ea2019-09-11 19:48:58 +02003903 client_context.minimum_version = ssl.TLSVersion.TLSv1
Christian Heimesf6c6b582021-03-18 23:06:50 +01003904 seclevel_workaround(client_context, server_context)
3905
Christian Heimes698dde12018-02-27 11:54:43 +01003906 with ThreadedEchoServer(context=server_context) as server:
3907 with client_context.wrap_socket(socket.socket(),
3908 server_hostname=hostname) as s:
3909 with self.assertRaises(ssl.SSLError) as e:
3910 s.connect((HOST, server.port))
3911 self.assertIn("alert", str(e.exception))
3912
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02003913 @requires_minimum_version
3914 @requires_tls_version('SSLv3')
Christian Heimes698dde12018-02-27 11:54:43 +01003915 def test_min_max_version_sslv3(self):
3916 client_context, server_context, hostname = testing_context()
3917 server_context.minimum_version = ssl.TLSVersion.SSLv3
3918 client_context.minimum_version = ssl.TLSVersion.SSLv3
3919 client_context.maximum_version = ssl.TLSVersion.SSLv3
Christian Heimesf6c6b582021-03-18 23:06:50 +01003920 seclevel_workaround(client_context, server_context)
3921
Christian Heimes698dde12018-02-27 11:54:43 +01003922 with ThreadedEchoServer(context=server_context) as server:
3923 with client_context.wrap_socket(socket.socket(),
3924 server_hostname=hostname) as s:
3925 s.connect((HOST, server.port))
3926 self.assertEqual(s.version(), 'SSLv3')
3927
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003928 @unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL")
3929 def test_default_ecdh_curve(self):
3930 # Issue #21015: elliptic curve-based Diffie Hellman key exchange
3931 # should be enabled by default on SSL contexts.
Christian Heimesa170fa12017-09-15 20:27:30 +02003932 context = ssl.SSLContext(ssl.PROTOCOL_TLS)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003933 context.load_cert_chain(CERTFILE)
Christian Heimescb5b68a2017-09-07 18:07:00 -07003934 # TLSv1.3 defaults to PFS key agreement and no longer has KEA in
3935 # cipher name.
3936 context.options |= ssl.OP_NO_TLSv1_3
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003937 # Prior to OpenSSL 1.0.0, ECDH ciphers have to be enabled
3938 # explicitly using the 'ECCdraft' cipher alias. Otherwise,
3939 # our default cipher list should prefer ECDH-based ciphers
3940 # automatically.
3941 if ssl.OPENSSL_VERSION_INFO < (1, 0, 0):
3942 context.set_ciphers("ECCdraft:ECDH")
3943 with ThreadedEchoServer(context=context) as server:
3944 with context.wrap_socket(socket.socket()) as s:
3945 s.connect((HOST, server.port))
3946 self.assertIn("ECDH", s.cipher()[0])
3947
3948 @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES,
3949 "'tls-unique' channel binding not available")
3950 def test_tls_unique_channel_binding(self):
3951 """Test tls-unique channel binding."""
3952 if support.verbose:
3953 sys.stdout.write("\n")
3954
Christian Heimes05d9fe32018-02-27 08:55:39 +01003955 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01003956
3957 server = ThreadedEchoServer(context=server_context,
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003958 chatty=True,
3959 connectionchatty=False)
Christian Heimes05d9fe32018-02-27 08:55:39 +01003960
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003961 with server:
Christian Heimes05d9fe32018-02-27 08:55:39 +01003962 with client_context.wrap_socket(
3963 socket.socket(),
3964 server_hostname=hostname) as s:
3965 s.connect((HOST, server.port))
3966 # get the data
3967 cb_data = s.get_channel_binding("tls-unique")
3968 if support.verbose:
3969 sys.stdout.write(
3970 " got channel binding data: {0!r}\n".format(cb_data))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003971
Christian Heimes05d9fe32018-02-27 08:55:39 +01003972 # check if it is sane
3973 self.assertIsNotNone(cb_data)
Christian Heimes529525f2018-05-23 22:24:45 +02003974 if s.version() == 'TLSv1.3':
3975 self.assertEqual(len(cb_data), 48)
3976 else:
3977 self.assertEqual(len(cb_data), 12) # True for TLSv1
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003978
Christian Heimes05d9fe32018-02-27 08:55:39 +01003979 # and compare with the peers version
3980 s.write(b"CB tls-unique\n")
3981 peer_data_repr = s.read().strip()
3982 self.assertEqual(peer_data_repr,
3983 repr(cb_data).encode("us-ascii"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003984
3985 # now, again
Christian Heimes05d9fe32018-02-27 08:55:39 +01003986 with client_context.wrap_socket(
3987 socket.socket(),
3988 server_hostname=hostname) as s:
3989 s.connect((HOST, server.port))
3990 new_cb_data = s.get_channel_binding("tls-unique")
3991 if support.verbose:
3992 sys.stdout.write(
3993 "got another channel binding data: {0!r}\n".format(
3994 new_cb_data)
3995 )
3996 # is it really unique
3997 self.assertNotEqual(cb_data, new_cb_data)
3998 self.assertIsNotNone(cb_data)
Christian Heimes529525f2018-05-23 22:24:45 +02003999 if s.version() == 'TLSv1.3':
4000 self.assertEqual(len(cb_data), 48)
4001 else:
4002 self.assertEqual(len(cb_data), 12) # True for TLSv1
Christian Heimes05d9fe32018-02-27 08:55:39 +01004003 s.write(b"CB tls-unique\n")
4004 peer_data_repr = s.read().strip()
4005 self.assertEqual(peer_data_repr,
4006 repr(new_cb_data).encode("us-ascii"))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004007
4008 def test_compression(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004009 client_context, server_context, hostname = testing_context()
4010 stats = server_params_test(client_context, server_context,
4011 chatty=True, connectionchatty=True,
4012 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004013 if support.verbose:
4014 sys.stdout.write(" got compression: {!r}\n".format(stats['compression']))
4015 self.assertIn(stats['compression'], { None, 'ZLIB', 'RLE' })
4016
4017 @unittest.skipUnless(hasattr(ssl, 'OP_NO_COMPRESSION'),
4018 "ssl.OP_NO_COMPRESSION needed for this test")
4019 def test_compression_disabled(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004020 client_context, server_context, hostname = testing_context()
4021 client_context.options |= ssl.OP_NO_COMPRESSION
4022 server_context.options |= ssl.OP_NO_COMPRESSION
4023 stats = server_params_test(client_context, server_context,
4024 chatty=True, connectionchatty=True,
4025 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004026 self.assertIs(stats['compression'], None)
4027
Paul Monsonf3550692019-06-19 13:09:54 -07004028 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004029 def test_dh_params(self):
4030 # Check we can get a connection with ephemeral Diffie-Hellman
Christian Heimesa170fa12017-09-15 20:27:30 +02004031 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004032 # test scenario needs TLS <= 1.2
4033 client_context.options |= ssl.OP_NO_TLSv1_3
Christian Heimesa170fa12017-09-15 20:27:30 +02004034 server_context.load_dh_params(DHFILE)
4035 server_context.set_ciphers("kEDH")
Christian Heimes05d9fe32018-02-27 08:55:39 +01004036 server_context.options |= ssl.OP_NO_TLSv1_3
Christian Heimesa170fa12017-09-15 20:27:30 +02004037 stats = server_params_test(client_context, server_context,
4038 chatty=True, connectionchatty=True,
4039 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004040 cipher = stats["cipher"][0]
4041 parts = cipher.split("-")
4042 if "ADH" not in parts and "EDH" not in parts and "DHE" not in parts:
4043 self.fail("Non-DH cipher: " + cipher[0])
4044
Christian Heimesb7b92252018-02-25 09:49:31 +01004045 @unittest.skipUnless(HAVE_SECP_CURVES, "needs secp384r1 curve support")
Christian Heimes05d9fe32018-02-27 08:55:39 +01004046 @unittest.skipIf(IS_OPENSSL_1_1_1, "TODO: Test doesn't work on 1.1.1")
Christian Heimesb7b92252018-02-25 09:49:31 +01004047 def test_ecdh_curve(self):
4048 # server secp384r1, client auto
4049 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004050
Christian Heimesb7b92252018-02-25 09:49:31 +01004051 server_context.set_ecdh_curve("secp384r1")
4052 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
4053 server_context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
4054 stats = server_params_test(client_context, server_context,
4055 chatty=True, connectionchatty=True,
4056 sni_name=hostname)
4057
4058 # server auto, client secp384r1
4059 client_context, server_context, hostname = testing_context()
4060 client_context.set_ecdh_curve("secp384r1")
4061 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
4062 server_context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
4063 stats = server_params_test(client_context, server_context,
4064 chatty=True, connectionchatty=True,
4065 sni_name=hostname)
4066
4067 # server / client curve mismatch
4068 client_context, server_context, hostname = testing_context()
4069 client_context.set_ecdh_curve("prime256v1")
4070 server_context.set_ecdh_curve("secp384r1")
4071 server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
4072 server_context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
4073 try:
4074 stats = server_params_test(client_context, server_context,
4075 chatty=True, connectionchatty=True,
4076 sni_name=hostname)
4077 except ssl.SSLError:
4078 pass
4079 else:
4080 # OpenSSL 1.0.2 does not fail although it should.
Christian Heimes05d9fe32018-02-27 08:55:39 +01004081 if IS_OPENSSL_1_1_0:
Christian Heimesb7b92252018-02-25 09:49:31 +01004082 self.fail("mismatch curve did not fail")
4083
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004084 def test_selected_alpn_protocol(self):
4085 # selected_alpn_protocol() is None unless ALPN is used.
Christian Heimesa170fa12017-09-15 20:27:30 +02004086 client_context, server_context, hostname = testing_context()
4087 stats = server_params_test(client_context, server_context,
4088 chatty=True, connectionchatty=True,
4089 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004090 self.assertIs(stats['client_alpn_protocol'], None)
4091
4092 @unittest.skipUnless(ssl.HAS_ALPN, "ALPN support required")
4093 def test_selected_alpn_protocol_if_server_uses_alpn(self):
4094 # selected_alpn_protocol() is None unless ALPN is used by the client.
Christian Heimesa170fa12017-09-15 20:27:30 +02004095 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004096 server_context.set_alpn_protocols(['foo', 'bar'])
4097 stats = server_params_test(client_context, server_context,
Christian Heimesa170fa12017-09-15 20:27:30 +02004098 chatty=True, connectionchatty=True,
4099 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004100 self.assertIs(stats['client_alpn_protocol'], None)
4101
4102 @unittest.skipUnless(ssl.HAS_ALPN, "ALPN support needed for this test")
4103 def test_alpn_protocols(self):
4104 server_protocols = ['foo', 'bar', 'milkshake']
4105 protocol_tests = [
4106 (['foo', 'bar'], 'foo'),
4107 (['bar', 'foo'], 'foo'),
4108 (['milkshake'], 'milkshake'),
4109 (['http/3.0', 'http/4.0'], None)
4110 ]
4111 for client_protocols, expected in protocol_tests:
Christian Heimesa170fa12017-09-15 20:27:30 +02004112 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004113 server_context.set_alpn_protocols(server_protocols)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004114 client_context.set_alpn_protocols(client_protocols)
4115
4116 try:
4117 stats = server_params_test(client_context,
4118 server_context,
4119 chatty=True,
Christian Heimesa170fa12017-09-15 20:27:30 +02004120 connectionchatty=True,
4121 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004122 except ssl.SSLError as e:
4123 stats = e
4124
Christian Heimes05d9fe32018-02-27 08:55:39 +01004125 if (expected is None and IS_OPENSSL_1_1_0
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004126 and ssl.OPENSSL_VERSION_INFO < (1, 1, 0, 6)):
4127 # OpenSSL 1.1.0 to 1.1.0e raises handshake error
4128 self.assertIsInstance(stats, ssl.SSLError)
4129 else:
4130 msg = "failed trying %s (s) and %s (c).\n" \
4131 "was expecting %s, but got %%s from the %%s" \
4132 % (str(server_protocols), str(client_protocols),
4133 str(expected))
4134 client_result = stats['client_alpn_protocol']
4135 self.assertEqual(client_result, expected,
4136 msg % (client_result, "client"))
4137 server_result = stats['server_alpn_protocols'][-1] \
4138 if len(stats['server_alpn_protocols']) else 'nothing'
4139 self.assertEqual(server_result, expected,
4140 msg % (server_result, "server"))
4141
4142 def test_selected_npn_protocol(self):
4143 # selected_npn_protocol() is None unless NPN is used
Christian Heimesa170fa12017-09-15 20:27:30 +02004144 client_context, server_context, hostname = testing_context()
4145 stats = server_params_test(client_context, server_context,
4146 chatty=True, connectionchatty=True,
4147 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004148 self.assertIs(stats['client_npn_protocol'], None)
4149
4150 @unittest.skipUnless(ssl.HAS_NPN, "NPN support needed for this test")
4151 def test_npn_protocols(self):
4152 server_protocols = ['http/1.1', 'spdy/2']
4153 protocol_tests = [
4154 (['http/1.1', 'spdy/2'], 'http/1.1'),
4155 (['spdy/2', 'http/1.1'], 'http/1.1'),
4156 (['spdy/2', 'test'], 'spdy/2'),
4157 (['abc', 'def'], 'abc')
4158 ]
4159 for client_protocols, expected in protocol_tests:
Christian Heimesa170fa12017-09-15 20:27:30 +02004160 client_context, server_context, hostname = testing_context()
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004161 server_context.set_npn_protocols(server_protocols)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004162 client_context.set_npn_protocols(client_protocols)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004163 stats = server_params_test(client_context, server_context,
Christian Heimesa170fa12017-09-15 20:27:30 +02004164 chatty=True, connectionchatty=True,
4165 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004166 msg = "failed trying %s (s) and %s (c).\n" \
4167 "was expecting %s, but got %%s from the %%s" \
4168 % (str(server_protocols), str(client_protocols),
4169 str(expected))
4170 client_result = stats['client_npn_protocol']
4171 self.assertEqual(client_result, expected, msg % (client_result, "client"))
4172 server_result = stats['server_npn_protocols'][-1] \
4173 if len(stats['server_npn_protocols']) else 'nothing'
4174 self.assertEqual(server_result, expected, msg % (server_result, "server"))
4175
4176 def sni_contexts(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004177 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004178 server_context.load_cert_chain(SIGNED_CERTFILE)
Christian Heimesa170fa12017-09-15 20:27:30 +02004179 other_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004180 other_context.load_cert_chain(SIGNED_CERTFILE2)
Christian Heimesa170fa12017-09-15 20:27:30 +02004181 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004182 client_context.load_verify_locations(SIGNING_CA)
4183 return server_context, other_context, client_context
4184
4185 def check_common_name(self, stats, name):
4186 cert = stats['peercert']
4187 self.assertIn((('commonName', name),), cert['subject'])
4188
4189 @needs_sni
4190 def test_sni_callback(self):
4191 calls = []
4192 server_context, other_context, client_context = self.sni_contexts()
4193
Christian Heimesa170fa12017-09-15 20:27:30 +02004194 client_context.check_hostname = False
4195
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004196 def servername_cb(ssl_sock, server_name, initial_context):
4197 calls.append((server_name, initial_context))
4198 if server_name is not None:
4199 ssl_sock.context = other_context
4200 server_context.set_servername_callback(servername_cb)
4201
4202 stats = server_params_test(client_context, server_context,
4203 chatty=True,
4204 sni_name='supermessage')
4205 # The hostname was fetched properly, and the certificate was
4206 # changed for the connection.
4207 self.assertEqual(calls, [("supermessage", server_context)])
4208 # CERTFILE4 was selected
4209 self.check_common_name(stats, 'fakehostname')
4210
4211 calls = []
4212 # The callback is called with server_name=None
4213 stats = server_params_test(client_context, server_context,
4214 chatty=True,
4215 sni_name=None)
4216 self.assertEqual(calls, [(None, server_context)])
Christian Heimesa170fa12017-09-15 20:27:30 +02004217 self.check_common_name(stats, SIGNED_CERTFILE_HOSTNAME)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004218
4219 # Check disabling the callback
4220 calls = []
4221 server_context.set_servername_callback(None)
4222
4223 stats = server_params_test(client_context, server_context,
4224 chatty=True,
4225 sni_name='notfunny')
4226 # Certificate didn't change
Christian Heimesa170fa12017-09-15 20:27:30 +02004227 self.check_common_name(stats, SIGNED_CERTFILE_HOSTNAME)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004228 self.assertEqual(calls, [])
4229
4230 @needs_sni
4231 def test_sni_callback_alert(self):
4232 # Returning a TLS alert is reflected to the connecting client
4233 server_context, other_context, client_context = self.sni_contexts()
4234
4235 def cb_returning_alert(ssl_sock, server_name, initial_context):
4236 return ssl.ALERT_DESCRIPTION_ACCESS_DENIED
4237 server_context.set_servername_callback(cb_returning_alert)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004238 with self.assertRaises(ssl.SSLError) as cm:
4239 stats = server_params_test(client_context, server_context,
4240 chatty=False,
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004241 sni_name='supermessage')
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004242 self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_ACCESS_DENIED')
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004243
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004244 @needs_sni
4245 def test_sni_callback_raising(self):
4246 # Raising fails the connection with a TLS handshake failure alert.
4247 server_context, other_context, client_context = self.sni_contexts()
4248
4249 def cb_raising(ssl_sock, server_name, initial_context):
4250 1/0
4251 server_context.set_servername_callback(cb_raising)
4252
Victor Stinner00253502019-06-03 03:51:43 +02004253 with support.catch_unraisable_exception() as catch:
4254 with self.assertRaises(ssl.SSLError) as cm:
4255 stats = server_params_test(client_context, server_context,
4256 chatty=False,
4257 sni_name='supermessage')
4258
4259 self.assertEqual(cm.exception.reason,
4260 'SSLV3_ALERT_HANDSHAKE_FAILURE')
4261 self.assertEqual(catch.unraisable.exc_type, ZeroDivisionError)
Antoine Pitrou50b24d02013-04-11 20:48:42 +02004262
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004263 @needs_sni
4264 def test_sni_callback_wrong_return_type(self):
4265 # Returning the wrong return type terminates the TLS connection
4266 # with an internal error alert.
4267 server_context, other_context, client_context = self.sni_contexts()
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004268
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004269 def cb_wrong_return_type(ssl_sock, server_name, initial_context):
4270 return "foo"
4271 server_context.set_servername_callback(cb_wrong_return_type)
4272
Victor Stinner00253502019-06-03 03:51:43 +02004273 with support.catch_unraisable_exception() as catch:
4274 with self.assertRaises(ssl.SSLError) as cm:
4275 stats = server_params_test(client_context, server_context,
4276 chatty=False,
4277 sni_name='supermessage')
4278
4279
4280 self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_INTERNAL_ERROR')
4281 self.assertEqual(catch.unraisable.exc_type, TypeError)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004282
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004283 def test_shared_ciphers(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004284 client_context, server_context, hostname = testing_context()
Christian Heimese8eb6cb2018-05-22 22:50:12 +02004285 client_context.set_ciphers("AES128:AES256")
4286 server_context.set_ciphers("AES256")
4287 expected_algs = [
4288 "AES256", "AES-256",
4289 # TLS 1.3 ciphers are always enabled
4290 "TLS_CHACHA20", "TLS_AES",
4291 ]
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004292
Christian Heimesa170fa12017-09-15 20:27:30 +02004293 stats = server_params_test(client_context, server_context,
4294 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004295 ciphers = stats['server_shared_ciphers'][0]
4296 self.assertGreater(len(ciphers), 0)
4297 for name, tls_version, bits in ciphers:
Christian Heimese8eb6cb2018-05-22 22:50:12 +02004298 if not any(alg in name for alg in expected_algs):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004299 self.fail(name)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004300
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004301 def test_read_write_after_close_raises_valuerror(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004302 client_context, server_context, hostname = testing_context()
4303 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004304
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004305 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02004306 s = client_context.wrap_socket(socket.socket(),
4307 server_hostname=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004308 s.connect((HOST, server.port))
4309 s.close()
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004310
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004311 self.assertRaises(ValueError, s.read, 1024)
4312 self.assertRaises(ValueError, s.write, b'hello')
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004313
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004314 def test_sendfile(self):
4315 TEST_DATA = b"x" * 512
Hai Shia7f5d932020-08-04 00:41:24 +08004316 with open(os_helper.TESTFN, 'wb') as f:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004317 f.write(TEST_DATA)
Hai Shia7f5d932020-08-04 00:41:24 +08004318 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesa170fa12017-09-15 20:27:30 +02004319 context = ssl.SSLContext(ssl.PROTOCOL_TLS)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004320 context.verify_mode = ssl.CERT_REQUIRED
Christian Heimesbd5c7d22018-01-20 15:16:30 +01004321 context.load_verify_locations(SIGNING_CA)
4322 context.load_cert_chain(SIGNED_CERTFILE)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004323 server = ThreadedEchoServer(context=context, chatty=False)
4324 with server:
4325 with context.wrap_socket(socket.socket()) as s:
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004326 s.connect((HOST, server.port))
Hai Shia7f5d932020-08-04 00:41:24 +08004327 with open(os_helper.TESTFN, 'rb') as file:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004328 s.sendfile(file)
4329 self.assertEqual(s.recv(1024), TEST_DATA)
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004330
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004331 def test_session(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004332 client_context, server_context, hostname = testing_context()
Christian Heimes05d9fe32018-02-27 08:55:39 +01004333 # TODO: sessions aren't compatible with TLSv1.3 yet
4334 client_context.options |= ssl.OP_NO_TLSv1_3
Antoine Pitrou60a26e02013-07-20 19:35:16 +02004335
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004336 # first connection without session
Christian Heimesa170fa12017-09-15 20:27:30 +02004337 stats = server_params_test(client_context, server_context,
4338 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004339 session = stats['session']
4340 self.assertTrue(session.id)
4341 self.assertGreater(session.time, 0)
4342 self.assertGreater(session.timeout, 0)
4343 self.assertTrue(session.has_ticket)
4344 if ssl.OPENSSL_VERSION_INFO > (1, 0, 1):
4345 self.assertGreater(session.ticket_lifetime_hint, 0)
4346 self.assertFalse(stats['session_reused'])
4347 sess_stat = server_context.session_stats()
4348 self.assertEqual(sess_stat['accept'], 1)
4349 self.assertEqual(sess_stat['hits'], 0)
Giampaolo Rodola'915d1412014-06-11 03:54:30 +02004350
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004351 # reuse session
Christian Heimesa170fa12017-09-15 20:27:30 +02004352 stats = server_params_test(client_context, server_context,
4353 session=session, sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004354 sess_stat = server_context.session_stats()
4355 self.assertEqual(sess_stat['accept'], 2)
4356 self.assertEqual(sess_stat['hits'], 1)
4357 self.assertTrue(stats['session_reused'])
4358 session2 = stats['session']
4359 self.assertEqual(session2.id, session.id)
4360 self.assertEqual(session2, session)
4361 self.assertIsNot(session2, session)
4362 self.assertGreaterEqual(session2.time, session.time)
4363 self.assertGreaterEqual(session2.timeout, session.timeout)
Christian Heimes99a65702016-09-10 23:44:53 +02004364
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004365 # another one without session
Christian Heimesa170fa12017-09-15 20:27:30 +02004366 stats = server_params_test(client_context, server_context,
4367 sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004368 self.assertFalse(stats['session_reused'])
4369 session3 = stats['session']
4370 self.assertNotEqual(session3.id, session.id)
4371 self.assertNotEqual(session3, session)
4372 sess_stat = server_context.session_stats()
4373 self.assertEqual(sess_stat['accept'], 3)
4374 self.assertEqual(sess_stat['hits'], 1)
Christian Heimes99a65702016-09-10 23:44:53 +02004375
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004376 # reuse session again
Christian Heimesa170fa12017-09-15 20:27:30 +02004377 stats = server_params_test(client_context, server_context,
4378 session=session, sni_name=hostname)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004379 self.assertTrue(stats['session_reused'])
4380 session4 = stats['session']
4381 self.assertEqual(session4.id, session.id)
4382 self.assertEqual(session4, session)
4383 self.assertGreaterEqual(session4.time, session.time)
4384 self.assertGreaterEqual(session4.timeout, session.timeout)
4385 sess_stat = server_context.session_stats()
4386 self.assertEqual(sess_stat['accept'], 4)
4387 self.assertEqual(sess_stat['hits'], 2)
Christian Heimes99a65702016-09-10 23:44:53 +02004388
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004389 def test_session_handling(self):
Christian Heimesa170fa12017-09-15 20:27:30 +02004390 client_context, server_context, hostname = testing_context()
4391 client_context2, _, _ = testing_context()
Christian Heimes99a65702016-09-10 23:44:53 +02004392
Christian Heimes05d9fe32018-02-27 08:55:39 +01004393 # TODO: session reuse does not work with TLSv1.3
Christian Heimesa170fa12017-09-15 20:27:30 +02004394 client_context.options |= ssl.OP_NO_TLSv1_3
4395 client_context2.options |= ssl.OP_NO_TLSv1_3
Christian Heimescb5b68a2017-09-07 18:07:00 -07004396
Christian Heimesa170fa12017-09-15 20:27:30 +02004397 server = ThreadedEchoServer(context=server_context, chatty=False)
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004398 with server:
Christian Heimesa170fa12017-09-15 20:27:30 +02004399 with client_context.wrap_socket(socket.socket(),
4400 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004401 # session is None before handshake
4402 self.assertEqual(s.session, None)
4403 self.assertEqual(s.session_reused, None)
4404 s.connect((HOST, server.port))
4405 session = s.session
4406 self.assertTrue(session)
4407 with self.assertRaises(TypeError) as e:
4408 s.session = object
Ned Deily4531ec72018-06-11 20:26:28 -04004409 self.assertEqual(str(e.exception), 'Value is not a SSLSession.')
Christian Heimes99a65702016-09-10 23:44:53 +02004410
Christian Heimesa170fa12017-09-15 20:27:30 +02004411 with client_context.wrap_socket(socket.socket(),
4412 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004413 s.connect((HOST, server.port))
4414 # cannot set session after handshake
4415 with self.assertRaises(ValueError) as e:
4416 s.session = session
4417 self.assertEqual(str(e.exception),
4418 'Cannot set session after handshake.')
Christian Heimes99a65702016-09-10 23:44:53 +02004419
Christian Heimesa170fa12017-09-15 20:27:30 +02004420 with client_context.wrap_socket(socket.socket(),
4421 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004422 # can set session before handshake and before the
4423 # connection was established
4424 s.session = session
4425 s.connect((HOST, server.port))
4426 self.assertEqual(s.session.id, session.id)
4427 self.assertEqual(s.session, session)
4428 self.assertEqual(s.session_reused, True)
Christian Heimes99a65702016-09-10 23:44:53 +02004429
Christian Heimesa170fa12017-09-15 20:27:30 +02004430 with client_context2.wrap_socket(socket.socket(),
4431 server_hostname=hostname) as s:
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004432 # cannot re-use session with a different SSLContext
4433 with self.assertRaises(ValueError) as e:
Christian Heimes99a65702016-09-10 23:44:53 +02004434 s.session = session
4435 s.connect((HOST, server.port))
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004436 self.assertEqual(str(e.exception),
4437 'Session refers to a different SSLContext.')
Christian Heimes99a65702016-09-10 23:44:53 +02004438
Antoine Pitrou8abdb8a2011-12-20 10:13:40 +01004439
Christian Heimesdf6ac7e2019-09-26 17:02:59 +02004440@unittest.skipUnless(has_tls_version('TLSv1_3'), "Test needs TLS 1.3")
Christian Heimes9fb051f2018-09-23 08:32:31 +02004441class TestPostHandshakeAuth(unittest.TestCase):
4442 def test_pha_setter(self):
4443 protocols = [
4444 ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS_SERVER, ssl.PROTOCOL_TLS_CLIENT
4445 ]
4446 for protocol in protocols:
4447 ctx = ssl.SSLContext(protocol)
4448 self.assertEqual(ctx.post_handshake_auth, False)
4449
4450 ctx.post_handshake_auth = True
4451 self.assertEqual(ctx.post_handshake_auth, True)
4452
4453 ctx.verify_mode = ssl.CERT_REQUIRED
4454 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
4455 self.assertEqual(ctx.post_handshake_auth, True)
4456
4457 ctx.post_handshake_auth = False
4458 self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
4459 self.assertEqual(ctx.post_handshake_auth, False)
4460
4461 ctx.verify_mode = ssl.CERT_OPTIONAL
4462 ctx.post_handshake_auth = True
4463 self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
4464 self.assertEqual(ctx.post_handshake_auth, True)
4465
4466 def test_pha_required(self):
4467 client_context, server_context, hostname = testing_context()
4468 server_context.post_handshake_auth = True
4469 server_context.verify_mode = ssl.CERT_REQUIRED
4470 client_context.post_handshake_auth = True
4471 client_context.load_cert_chain(SIGNED_CERTFILE)
4472
4473 server = ThreadedEchoServer(context=server_context, chatty=False)
4474 with server:
4475 with client_context.wrap_socket(socket.socket(),
4476 server_hostname=hostname) as s:
4477 s.connect((HOST, server.port))
4478 s.write(b'HASCERT')
4479 self.assertEqual(s.recv(1024), b'FALSE\n')
4480 s.write(b'PHA')
4481 self.assertEqual(s.recv(1024), b'OK\n')
4482 s.write(b'HASCERT')
4483 self.assertEqual(s.recv(1024), b'TRUE\n')
4484 # PHA method just returns true when cert is already available
4485 s.write(b'PHA')
4486 self.assertEqual(s.recv(1024), b'OK\n')
4487 s.write(b'GETCERT')
4488 cert_text = s.recv(4096).decode('us-ascii')
4489 self.assertIn('Python Software Foundation CA', cert_text)
4490
4491 def test_pha_required_nocert(self):
4492 client_context, server_context, hostname = testing_context()
4493 server_context.post_handshake_auth = True
4494 server_context.verify_mode = ssl.CERT_REQUIRED
4495 client_context.post_handshake_auth = True
4496
Victor Stinner73ea5462019-07-09 14:33:49 +02004497 # Ignore expected SSLError in ConnectionHandler of ThreadedEchoServer
4498 # (it is only raised sometimes on Windows)
Hai Shie80697d2020-05-28 06:10:27 +08004499 with threading_helper.catch_threading_exception() as cm:
Victor Stinner73ea5462019-07-09 14:33:49 +02004500 server = ThreadedEchoServer(context=server_context, chatty=False)
4501 with server:
4502 with client_context.wrap_socket(socket.socket(),
4503 server_hostname=hostname) as s:
4504 s.connect((HOST, server.port))
4505 s.write(b'PHA')
4506 # receive CertificateRequest
4507 self.assertEqual(s.recv(1024), b'OK\n')
4508 # send empty Certificate + Finish
4509 s.write(b'HASCERT')
4510 # receive alert
4511 with self.assertRaisesRegex(
4512 ssl.SSLError,
4513 'tlsv13 alert certificate required'):
4514 s.recv(1024)
Christian Heimes9fb051f2018-09-23 08:32:31 +02004515
4516 def test_pha_optional(self):
4517 if support.verbose:
4518 sys.stdout.write("\n")
4519
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 client_context.load_cert_chain(SIGNED_CERTFILE)
4525
4526 # check CERT_OPTIONAL
4527 server_context.verify_mode = ssl.CERT_OPTIONAL
4528 server = ThreadedEchoServer(context=server_context, chatty=False)
4529 with server:
4530 with client_context.wrap_socket(socket.socket(),
4531 server_hostname=hostname) as s:
4532 s.connect((HOST, server.port))
4533 s.write(b'HASCERT')
4534 self.assertEqual(s.recv(1024), b'FALSE\n')
4535 s.write(b'PHA')
4536 self.assertEqual(s.recv(1024), b'OK\n')
4537 s.write(b'HASCERT')
4538 self.assertEqual(s.recv(1024), b'TRUE\n')
4539
4540 def test_pha_optional_nocert(self):
4541 if support.verbose:
4542 sys.stdout.write("\n")
4543
4544 client_context, server_context, hostname = testing_context()
4545 server_context.post_handshake_auth = True
4546 server_context.verify_mode = ssl.CERT_OPTIONAL
4547 client_context.post_handshake_auth = True
4548
4549 server = ThreadedEchoServer(context=server_context, chatty=False)
4550 with server:
4551 with client_context.wrap_socket(socket.socket(),
4552 server_hostname=hostname) as s:
4553 s.connect((HOST, server.port))
4554 s.write(b'HASCERT')
4555 self.assertEqual(s.recv(1024), b'FALSE\n')
4556 s.write(b'PHA')
4557 self.assertEqual(s.recv(1024), b'OK\n')
penguindustin96466302019-05-06 14:57:17 -04004558 # optional doesn't fail when client does not have a cert
Christian Heimes9fb051f2018-09-23 08:32:31 +02004559 s.write(b'HASCERT')
4560 self.assertEqual(s.recv(1024), b'FALSE\n')
4561
4562 def test_pha_no_pha_client(self):
4563 client_context, server_context, hostname = testing_context()
4564 server_context.post_handshake_auth = True
4565 server_context.verify_mode = ssl.CERT_REQUIRED
4566 client_context.load_cert_chain(SIGNED_CERTFILE)
4567
4568 server = ThreadedEchoServer(context=server_context, chatty=False)
4569 with server:
4570 with client_context.wrap_socket(socket.socket(),
4571 server_hostname=hostname) as s:
4572 s.connect((HOST, server.port))
4573 with self.assertRaisesRegex(ssl.SSLError, 'not server'):
4574 s.verify_client_post_handshake()
4575 s.write(b'PHA')
4576 self.assertIn(b'extension not received', s.recv(1024))
4577
4578 def test_pha_no_pha_server(self):
4579 # server doesn't have PHA enabled, cert is requested in handshake
4580 client_context, server_context, hostname = testing_context()
4581 server_context.verify_mode = ssl.CERT_REQUIRED
4582 client_context.post_handshake_auth = True
4583 client_context.load_cert_chain(SIGNED_CERTFILE)
4584
4585 server = ThreadedEchoServer(context=server_context, chatty=False)
4586 with server:
4587 with client_context.wrap_socket(socket.socket(),
4588 server_hostname=hostname) as s:
4589 s.connect((HOST, server.port))
4590 s.write(b'HASCERT')
4591 self.assertEqual(s.recv(1024), b'TRUE\n')
4592 # PHA doesn't fail if there is already a cert
4593 s.write(b'PHA')
4594 self.assertEqual(s.recv(1024), b'OK\n')
4595 s.write(b'HASCERT')
4596 self.assertEqual(s.recv(1024), b'TRUE\n')
4597
4598 def test_pha_not_tls13(self):
4599 # TLS 1.2
4600 client_context, server_context, hostname = testing_context()
4601 server_context.verify_mode = ssl.CERT_REQUIRED
4602 client_context.maximum_version = ssl.TLSVersion.TLSv1_2
4603 client_context.post_handshake_auth = True
4604 client_context.load_cert_chain(SIGNED_CERTFILE)
4605
4606 server = ThreadedEchoServer(context=server_context, chatty=False)
4607 with server:
4608 with client_context.wrap_socket(socket.socket(),
4609 server_hostname=hostname) as s:
4610 s.connect((HOST, server.port))
4611 # PHA fails for TLS != 1.3
4612 s.write(b'PHA')
4613 self.assertIn(b'WRONG_SSL_VERSION', s.recv(1024))
4614
Christian Heimesf0f59302019-07-01 08:29:17 +02004615 def test_bpo37428_pha_cert_none(self):
4616 # verify that post_handshake_auth does not implicitly enable cert
4617 # validation.
4618 hostname = SIGNED_CERTFILE_HOSTNAME
4619 client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4620 client_context.post_handshake_auth = True
4621 client_context.load_cert_chain(SIGNED_CERTFILE)
4622 # no cert validation and CA on client side
4623 client_context.check_hostname = False
4624 client_context.verify_mode = ssl.CERT_NONE
4625
4626 server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
4627 server_context.load_cert_chain(SIGNED_CERTFILE)
4628 server_context.load_verify_locations(SIGNING_CA)
4629 server_context.post_handshake_auth = True
4630 server_context.verify_mode = ssl.CERT_REQUIRED
4631
4632 server = ThreadedEchoServer(context=server_context, chatty=False)
4633 with server:
4634 with client_context.wrap_socket(socket.socket(),
4635 server_hostname=hostname) as s:
4636 s.connect((HOST, server.port))
4637 s.write(b'HASCERT')
4638 self.assertEqual(s.recv(1024), b'FALSE\n')
4639 s.write(b'PHA')
4640 self.assertEqual(s.recv(1024), b'OK\n')
4641 s.write(b'HASCERT')
4642 self.assertEqual(s.recv(1024), b'TRUE\n')
4643 # server cert has not been validated
4644 self.assertEqual(s.getpeercert(), {})
4645
Christian Heimes9fb051f2018-09-23 08:32:31 +02004646
Christian Heimesc7f70692019-05-31 11:44:05 +02004647HAS_KEYLOG = hasattr(ssl.SSLContext, 'keylog_filename')
4648requires_keylog = unittest.skipUnless(
4649 HAS_KEYLOG, 'test requires OpenSSL 1.1.1 with keylog callback')
4650
4651class TestSSLDebug(unittest.TestCase):
4652
Hai Shia7f5d932020-08-04 00:41:24 +08004653 def keylog_lines(self, fname=os_helper.TESTFN):
Christian Heimesc7f70692019-05-31 11:44:05 +02004654 with open(fname) as f:
4655 return len(list(f))
4656
4657 @requires_keylog
Paul Monsonf3550692019-06-19 13:09:54 -07004658 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004659 def test_keylog_defaults(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004660 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004661 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4662 self.assertEqual(ctx.keylog_filename, None)
4663
Hai Shia7f5d932020-08-04 00:41:24 +08004664 self.assertFalse(os.path.isfile(os_helper.TESTFN))
4665 ctx.keylog_filename = os_helper.TESTFN
4666 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
4667 self.assertTrue(os.path.isfile(os_helper.TESTFN))
Christian Heimesc7f70692019-05-31 11:44:05 +02004668 self.assertEqual(self.keylog_lines(), 1)
4669
4670 ctx.keylog_filename = None
4671 self.assertEqual(ctx.keylog_filename, None)
4672
4673 with self.assertRaises((IsADirectoryError, PermissionError)):
4674 # Windows raises PermissionError
4675 ctx.keylog_filename = os.path.dirname(
Hai Shia7f5d932020-08-04 00:41:24 +08004676 os.path.abspath(os_helper.TESTFN))
Christian Heimesc7f70692019-05-31 11:44:05 +02004677
4678 with self.assertRaises(TypeError):
4679 ctx.keylog_filename = 1
4680
4681 @requires_keylog
Paul Monsonf3550692019-06-19 13:09:54 -07004682 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004683 def test_keylog_filename(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004684 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004685 client_context, server_context, hostname = testing_context()
4686
Hai Shia7f5d932020-08-04 00:41:24 +08004687 client_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004688 server = ThreadedEchoServer(context=server_context, chatty=False)
4689 with server:
4690 with client_context.wrap_socket(socket.socket(),
4691 server_hostname=hostname) as s:
4692 s.connect((HOST, server.port))
4693 # header, 5 lines for TLS 1.3
4694 self.assertEqual(self.keylog_lines(), 6)
4695
4696 client_context.keylog_filename = None
Hai Shia7f5d932020-08-04 00:41:24 +08004697 server_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004698 server = ThreadedEchoServer(context=server_context, chatty=False)
4699 with server:
4700 with client_context.wrap_socket(socket.socket(),
4701 server_hostname=hostname) as s:
4702 s.connect((HOST, server.port))
4703 self.assertGreaterEqual(self.keylog_lines(), 11)
4704
Hai Shia7f5d932020-08-04 00:41:24 +08004705 client_context.keylog_filename = os_helper.TESTFN
4706 server_context.keylog_filename = os_helper.TESTFN
Christian Heimesc7f70692019-05-31 11:44:05 +02004707 server = ThreadedEchoServer(context=server_context, chatty=False)
4708 with server:
4709 with client_context.wrap_socket(socket.socket(),
4710 server_hostname=hostname) as s:
4711 s.connect((HOST, server.port))
4712 self.assertGreaterEqual(self.keylog_lines(), 21)
4713
4714 client_context.keylog_filename = None
4715 server_context.keylog_filename = None
4716
4717 @requires_keylog
4718 @unittest.skipIf(sys.flags.ignore_environment,
4719 "test is not compatible with ignore_environment")
Paul Monsonf3550692019-06-19 13:09:54 -07004720 @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows")
Christian Heimesc7f70692019-05-31 11:44:05 +02004721 def test_keylog_env(self):
Hai Shia7f5d932020-08-04 00:41:24 +08004722 self.addCleanup(os_helper.unlink, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004723 with unittest.mock.patch.dict(os.environ):
Hai Shia7f5d932020-08-04 00:41:24 +08004724 os.environ['SSLKEYLOGFILE'] = os_helper.TESTFN
4725 self.assertEqual(os.environ['SSLKEYLOGFILE'], os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004726
4727 ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
4728 self.assertEqual(ctx.keylog_filename, None)
4729
4730 ctx = ssl.create_default_context()
Hai Shia7f5d932020-08-04 00:41:24 +08004731 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004732
4733 ctx = ssl._create_stdlib_context()
Hai Shia7f5d932020-08-04 00:41:24 +08004734 self.assertEqual(ctx.keylog_filename, os_helper.TESTFN)
Christian Heimesc7f70692019-05-31 11:44:05 +02004735
4736 def test_msg_callback(self):
4737 client_context, server_context, hostname = testing_context()
4738
4739 def msg_cb(conn, direction, version, content_type, msg_type, data):
4740 pass
4741
4742 self.assertIs(client_context._msg_callback, None)
4743 client_context._msg_callback = msg_cb
4744 self.assertIs(client_context._msg_callback, msg_cb)
4745 with self.assertRaises(TypeError):
4746 client_context._msg_callback = object()
4747
4748 def test_msg_callback_tls12(self):
4749 client_context, server_context, hostname = testing_context()
4750 client_context.options |= ssl.OP_NO_TLSv1_3
4751
4752 msg = []
4753
4754 def msg_cb(conn, direction, version, content_type, msg_type, data):
4755 self.assertIsInstance(conn, ssl.SSLSocket)
4756 self.assertIsInstance(data, bytes)
4757 self.assertIn(direction, {'read', 'write'})
4758 msg.append((direction, version, content_type, msg_type))
4759
4760 client_context._msg_callback = msg_cb
4761
4762 server = ThreadedEchoServer(context=server_context, chatty=False)
4763 with server:
4764 with client_context.wrap_socket(socket.socket(),
4765 server_hostname=hostname) as s:
4766 s.connect((HOST, server.port))
4767
Christian Heimese35d1ba2019-06-03 20:40:15 +02004768 self.assertIn(
Christian Heimesc7f70692019-05-31 11:44:05 +02004769 ("read", TLSVersion.TLSv1_2, _TLSContentType.HANDSHAKE,
4770 _TLSMessageType.SERVER_KEY_EXCHANGE),
Christian Heimese35d1ba2019-06-03 20:40:15 +02004771 msg
4772 )
4773 self.assertIn(
Christian Heimesc7f70692019-05-31 11:44:05 +02004774 ("write", TLSVersion.TLSv1_2, _TLSContentType.CHANGE_CIPHER_SPEC,
4775 _TLSMessageType.CHANGE_CIPHER_SPEC),
Christian Heimese35d1ba2019-06-03 20:40:15 +02004776 msg
4777 )
Christian Heimesc7f70692019-05-31 11:44:05 +02004778
Christian Heimes77cde502021-03-21 16:13:09 +01004779 def test_msg_callback_deadlock_bpo43577(self):
4780 client_context, server_context, hostname = testing_context()
4781 server_context2 = testing_context()[1]
4782
4783 def msg_cb(conn, direction, version, content_type, msg_type, data):
4784 pass
4785
4786 def sni_cb(sock, servername, ctx):
4787 sock.context = server_context2
4788
4789 server_context._msg_callback = msg_cb
4790 server_context.sni_callback = sni_cb
4791
4792 server = ThreadedEchoServer(context=server_context, chatty=False)
4793 with server:
4794 with client_context.wrap_socket(socket.socket(),
4795 server_hostname=hostname) as s:
4796 s.connect((HOST, server.port))
4797 with client_context.wrap_socket(socket.socket(),
4798 server_hostname=hostname) as s:
4799 s.connect((HOST, server.port))
4800
Christian Heimesc7f70692019-05-31 11:44:05 +02004801
Thomas Woutersed03b412007-08-28 21:37:11 +00004802def test_main(verbose=False):
Antoine Pitrou15cee622010-08-04 16:45:21 +00004803 if support.verbose:
4804 plats = {
Antoine Pitrou15cee622010-08-04 16:45:21 +00004805 'Mac': platform.mac_ver,
4806 'Windows': platform.win32_ver,
4807 }
Petr Viktorin8b94b412018-05-16 11:51:18 -04004808 for name, func in plats.items():
4809 plat = func()
4810 if plat and plat[0]:
4811 plat = '%s %r' % (name, plat)
4812 break
4813 else:
4814 plat = repr(platform.platform())
Antoine Pitrou15cee622010-08-04 16:45:21 +00004815 print("test_ssl: testing with %r %r" %
4816 (ssl.OPENSSL_VERSION, ssl.OPENSSL_VERSION_INFO))
4817 print(" under %s" % plat)
Antoine Pitroud5323212010-10-22 18:19:07 +00004818 print(" HAS_SNI = %r" % ssl.HAS_SNI)
Antoine Pitrou609ef012013-03-29 18:09:06 +01004819 print(" OP_ALL = 0x%8x" % ssl.OP_ALL)
4820 try:
4821 print(" OP_NO_TLSv1_1 = 0x%8x" % ssl.OP_NO_TLSv1_1)
4822 except AttributeError:
4823 pass
Antoine Pitrou15cee622010-08-04 16:45:21 +00004824
Antoine Pitrou152efa22010-05-16 18:19:27 +00004825 for filename in [
Martin Panter3840b2a2016-03-27 01:53:46 +00004826 CERTFILE, BYTES_CERTFILE,
Antoine Pitrou152efa22010-05-16 18:19:27 +00004827 ONLYCERT, ONLYKEY, BYTES_ONLYCERT, BYTES_ONLYKEY,
Antoine Pitrou58ddc9d2013-01-05 21:20:29 +01004828 SIGNED_CERTFILE, SIGNED_CERTFILE2, SIGNING_CA,
Antoine Pitrou152efa22010-05-16 18:19:27 +00004829 BADCERT, BADKEY, EMPTYCERT]:
4830 if not os.path.exists(filename):
4831 raise support.TestFailed("Can't read certificate file %r" % filename)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004832
Martin Panter3840b2a2016-03-27 01:53:46 +00004833 tests = [
4834 ContextTests, BasicSocketTests, SSLErrorTests, MemoryBIOTests,
Christian Heimes9d50ab52018-02-27 10:17:30 +01004835 SSLObjectTests, SimpleBackgroundTests, ThreadedTests,
Christian Heimesc7f70692019-05-31 11:44:05 +02004836 TestPostHandshakeAuth, TestSSLDebug
Martin Panter3840b2a2016-03-27 01:53:46 +00004837 ]
Thomas Woutersed03b412007-08-28 21:37:11 +00004838
Benjamin Petersonee8712c2008-05-20 21:35:26 +00004839 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00004840 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00004841
Hai Shie80697d2020-05-28 06:10:27 +08004842 thread_info = threading_helper.threading_setup()
Antoine Pitrou480a1242010-04-28 21:37:09 +00004843 try:
4844 support.run_unittest(*tests)
4845 finally:
Hai Shie80697d2020-05-28 06:10:27 +08004846 threading_helper.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00004847
4848if __name__ == "__main__":
4849 test_main()