1919import weakref
2020import platform
2121import sysconfig
22+ import functools
2223try :
2324 import ctypes
2425except ImportError :
@@ -143,6 +144,87 @@ def data_file(*name):
143144OP_ENABLE_MIDDLEBOX_COMPAT = getattr (ssl , "OP_ENABLE_MIDDLEBOX_COMPAT" , 0 )
144145
145146
147+ def has_tls_protocol (protocol ):
148+ """Check if a TLS protocol is available and enabled
149+
150+ :param protocol: enum ssl._SSLMethod member or name
151+ :return: bool
152+ """
153+ if isinstance (protocol , str ):
154+ assert protocol .startswith ('PROTOCOL_' )
155+ protocol = getattr (ssl , protocol , None )
156+ if protocol is None :
157+ return False
158+ if protocol in {
159+ ssl .PROTOCOL_TLS , ssl .PROTOCOL_TLS_SERVER ,
160+ ssl .PROTOCOL_TLS_CLIENT
161+ }:
162+ # auto-negotiate protocols are always available
163+ return True
164+ name = protocol .name
165+ return has_tls_version (name [len ('PROTOCOL_' ):])
166+
167+
168+ @functools .lru_cache
169+ def has_tls_version (version ):
170+ """Check if a TLS/SSL version is enabled
171+
172+ :param version: TLS version name or ssl.TLSVersion member
173+ :return: bool
174+ """
175+ if version == "SSLv2" :
176+ # never supported and not even in TLSVersion enum
177+ return False
178+
179+ if isinstance (version , str ):
180+ version = ssl .TLSVersion .__members__ [version ]
181+
182+ # check compile time flags like ssl.HAS_TLSv1_2
183+ if not getattr (ssl , f'HAS_{ version .name } ' ):
184+ return False
185+
186+ # check runtime and dynamic crypto policy settings. A TLS version may
187+ # be compiled in but disabled by a policy or config option.
188+ ctx = ssl .SSLContext ()
189+ if (
190+ hasattr (ctx , 'minimum_version' ) and
191+ ctx .minimum_version != ssl .TLSVersion .MINIMUM_SUPPORTED and
192+ version < ctx .minimum_version
193+ ):
194+ return False
195+ if (
196+ hasattr (ctx , 'maximum_version' ) and
197+ ctx .maximum_version != ssl .TLSVersion .MAXIMUM_SUPPORTED and
198+ version > ctx .maximum_version
199+ ):
200+ return False
201+
202+ return True
203+
204+
205+ def requires_tls_version (version ):
206+ """Decorator to skip tests when a required TLS version is not available
207+
208+ :param version: TLS version name or ssl.TLSVersion member
209+ :return:
210+ """
211+ def decorator (func ):
212+ @functools .wraps (func )
213+ def wrapper (* args , ** kw ):
214+ if not has_tls_version (version ):
215+ raise unittest .SkipTest (f"{ version } is not available." )
216+ else :
217+ return func (* args , ** kw )
218+ return wrapper
219+ return decorator
220+
221+
222+ requires_minimum_version = unittest .skipUnless (
223+ hasattr (ssl .SSLContext , 'minimum_version' ),
224+ "required OpenSSL >= 1.1.0g"
225+ )
226+
227+
146228def handle_error (prefix ):
147229 exc_format = ' ' .join (traceback .format_exception (* sys .exc_info ()))
148230 if support .verbose :
@@ -1104,20 +1186,23 @@ def test_hostname_checks_common_name(self):
11041186 with self .assertRaises (AttributeError ):
11051187 ctx .hostname_checks_common_name = True
11061188
1107- @unittest .skipUnless (hasattr (ssl .SSLContext , 'minimum_version' ),
1108- "required OpenSSL 1.1.0g" )
1189+ @requires_minimum_version
11091190 @unittest .skipIf (IS_LIBRESSL , "see bpo-34001" )
11101191 def test_min_max_version (self ):
11111192 ctx = ssl .SSLContext (ssl .PROTOCOL_TLS_SERVER )
11121193 # OpenSSL default is MINIMUM_SUPPORTED, however some vendors like
11131194 # Fedora override the setting to TLS 1.0.
1195+ minimum_range = {
1196+ # stock OpenSSL
1197+ ssl .TLSVersion .MINIMUM_SUPPORTED ,
1198+ # Fedora 29 uses TLS 1.0 by default
1199+ ssl .TLSVersion .TLSv1 ,
1200+ # RHEL 8 uses TLS 1.2 by default
1201+ ssl .TLSVersion .TLSv1_2
1202+ }
1203+
11141204 self .assertIn (
1115- ctx .minimum_version ,
1116- {ssl .TLSVersion .MINIMUM_SUPPORTED ,
1117- # Fedora 29 uses TLS 1.0 by default
1118- ssl .TLSVersion .TLSv1 ,
1119- # RHEL 8 uses TLS 1.2 by default
1120- ssl .TLSVersion .TLSv1_2 }
1205+ ctx .minimum_version , minimum_range
11211206 )
11221207 self .assertEqual (
11231208 ctx .maximum_version , ssl .TLSVersion .MAXIMUM_SUPPORTED
@@ -1163,8 +1248,8 @@ def test_min_max_version(self):
11631248
11641249 ctx = ssl .SSLContext (ssl .PROTOCOL_TLSv1_1 )
11651250
1166- self .assertEqual (
1167- ctx .minimum_version , ssl . TLSVersion . MINIMUM_SUPPORTED
1251+ self .assertIn (
1252+ ctx .minimum_version , minimum_range
11681253 )
11691254 self .assertEqual (
11701255 ctx .maximum_version , ssl .TLSVersion .MAXIMUM_SUPPORTED
@@ -2717,6 +2802,8 @@ def test_echo(self):
27172802 for protocol in PROTOCOLS :
27182803 if protocol in {ssl .PROTOCOL_TLS_CLIENT , ssl .PROTOCOL_TLS_SERVER }:
27192804 continue
2805+ if not has_tls_protocol (protocol ):
2806+ continue
27202807 with self .subTest (protocol = ssl ._PROTOCOL_NAMES [protocol ]):
27212808 context = ssl .SSLContext (protocol )
27222809 context .load_cert_chain (CERTFILE )
@@ -3008,7 +3095,7 @@ def test_wrong_cert_tls12(self):
30083095 else :
30093096 self .fail ("Use of invalid cert should have failed!" )
30103097
3011- @unittest . skipUnless ( ssl . HAS_TLSv1_3 , "Test needs TLS 1.3" )
3098+ @requires_tls_version ( 'TLSv1_3' )
30123099 def test_wrong_cert_tls13 (self ):
30133100 client_context , server_context , hostname = testing_context ()
30143101 # load client cert that is not signed by trusted CA
@@ -3103,8 +3190,7 @@ def test_ssl_cert_verify_error(self):
31033190 self .assertIn (msg , repr (e ))
31043191 self .assertIn ('certificate verify failed' , repr (e ))
31053192
3106- @unittest .skipUnless (hasattr (ssl , 'PROTOCOL_SSLv2' ),
3107- "OpenSSL is compiled without SSLv2 support" )
3193+ @requires_tls_version ('SSLv2' )
31083194 def test_protocol_sslv2 (self ):
31093195 """Connecting to an SSLv2 server with various client options"""
31103196 if support .verbose :
@@ -3113,7 +3199,7 @@ def test_protocol_sslv2(self):
31133199 try_protocol_combo (ssl .PROTOCOL_SSLv2 , ssl .PROTOCOL_SSLv2 , True , ssl .CERT_OPTIONAL )
31143200 try_protocol_combo (ssl .PROTOCOL_SSLv2 , ssl .PROTOCOL_SSLv2 , True , ssl .CERT_REQUIRED )
31153201 try_protocol_combo (ssl .PROTOCOL_SSLv2 , ssl .PROTOCOL_TLS , False )
3116- if hasattr ( ssl , 'PROTOCOL_SSLv3 ' ):
3202+ if has_tls_version ( 'SSLv3 ' ):
31173203 try_protocol_combo (ssl .PROTOCOL_SSLv2 , ssl .PROTOCOL_SSLv3 , False )
31183204 try_protocol_combo (ssl .PROTOCOL_SSLv2 , ssl .PROTOCOL_TLSv1 , False )
31193205 # SSLv23 client with specific SSL options
@@ -3130,7 +3216,7 @@ def test_PROTOCOL_TLS(self):
31303216 """Connecting to an SSLv23 server with various client options"""
31313217 if support .verbose :
31323218 sys .stdout .write ("\n " )
3133- if hasattr ( ssl , 'PROTOCOL_SSLv2 ' ):
3219+ if has_tls_version ( 'SSLv2 ' ):
31343220 try :
31353221 try_protocol_combo (ssl .PROTOCOL_TLS , ssl .PROTOCOL_SSLv2 , True )
31363222 except OSError as x :
@@ -3139,42 +3225,44 @@ def test_PROTOCOL_TLS(self):
31393225 sys .stdout .write (
31403226 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n "
31413227 % str (x ))
3142- if hasattr ( ssl , 'PROTOCOL_SSLv3 ' ):
3228+ if has_tls_version ( 'SSLv3 ' ):
31433229 try_protocol_combo (ssl .PROTOCOL_TLS , ssl .PROTOCOL_SSLv3 , False )
31443230 try_protocol_combo (ssl .PROTOCOL_TLS , ssl .PROTOCOL_TLS , True )
3145- try_protocol_combo (ssl .PROTOCOL_TLS , ssl .PROTOCOL_TLSv1 , 'TLSv1' )
3231+ if has_tls_version ('TLSv1' ):
3232+ try_protocol_combo (ssl .PROTOCOL_TLS , ssl .PROTOCOL_TLSv1 , 'TLSv1' )
31463233
3147- if hasattr ( ssl , 'PROTOCOL_SSLv3 ' ):
3234+ if has_tls_version ( 'SSLv3 ' ):
31483235 try_protocol_combo (ssl .PROTOCOL_TLS , ssl .PROTOCOL_SSLv3 , False , ssl .CERT_OPTIONAL )
31493236 try_protocol_combo (ssl .PROTOCOL_TLS , ssl .PROTOCOL_TLS , True , ssl .CERT_OPTIONAL )
3150- try_protocol_combo (ssl .PROTOCOL_TLS , ssl .PROTOCOL_TLSv1 , 'TLSv1' , ssl .CERT_OPTIONAL )
3237+ if has_tls_version ('TLSv1' ):
3238+ try_protocol_combo (ssl .PROTOCOL_TLS , ssl .PROTOCOL_TLSv1 , 'TLSv1' , ssl .CERT_OPTIONAL )
31513239
3152- if hasattr ( ssl , 'PROTOCOL_SSLv3 ' ):
3240+ if has_tls_version ( 'SSLv3 ' ):
31533241 try_protocol_combo (ssl .PROTOCOL_TLS , ssl .PROTOCOL_SSLv3 , False , ssl .CERT_REQUIRED )
31543242 try_protocol_combo (ssl .PROTOCOL_TLS , ssl .PROTOCOL_TLS , True , ssl .CERT_REQUIRED )
3155- try_protocol_combo (ssl .PROTOCOL_TLS , ssl .PROTOCOL_TLSv1 , 'TLSv1' , ssl .CERT_REQUIRED )
3243+ if has_tls_version ('TLSv1' ):
3244+ try_protocol_combo (ssl .PROTOCOL_TLS , ssl .PROTOCOL_TLSv1 , 'TLSv1' , ssl .CERT_REQUIRED )
31563245
31573246 # Server with specific SSL options
3158- if hasattr ( ssl , 'PROTOCOL_SSLv3 ' ):
3247+ if has_tls_version ( 'SSLv3 ' ):
31593248 try_protocol_combo (ssl .PROTOCOL_TLS , ssl .PROTOCOL_SSLv3 , False ,
31603249 server_options = ssl .OP_NO_SSLv3 )
31613250 # Will choose TLSv1
31623251 try_protocol_combo (ssl .PROTOCOL_TLS , ssl .PROTOCOL_TLS , True ,
31633252 server_options = ssl .OP_NO_SSLv2 | ssl .OP_NO_SSLv3 )
3164- try_protocol_combo ( ssl . PROTOCOL_TLS , ssl . PROTOCOL_TLSv1 , False ,
3165- server_options = ssl .OP_NO_TLSv1 )
3166-
3253+ if has_tls_version ( 'TLSv1' ):
3254+ try_protocol_combo ( ssl . PROTOCOL_TLS , ssl .PROTOCOL_TLSv1 , False ,
3255+ server_options = ssl . OP_NO_TLSv1 )
31673256
3168- @unittest .skipUnless (hasattr (ssl , 'PROTOCOL_SSLv3' ),
3169- "OpenSSL is compiled without SSLv3 support" )
3257+ @requires_tls_version ('SSLv3' )
31703258 def test_protocol_sslv3 (self ):
31713259 """Connecting to an SSLv3 server with various client options"""
31723260 if support .verbose :
31733261 sys .stdout .write ("\n " )
31743262 try_protocol_combo (ssl .PROTOCOL_SSLv3 , ssl .PROTOCOL_SSLv3 , 'SSLv3' )
31753263 try_protocol_combo (ssl .PROTOCOL_SSLv3 , ssl .PROTOCOL_SSLv3 , 'SSLv3' , ssl .CERT_OPTIONAL )
31763264 try_protocol_combo (ssl .PROTOCOL_SSLv3 , ssl .PROTOCOL_SSLv3 , 'SSLv3' , ssl .CERT_REQUIRED )
3177- if hasattr ( ssl , 'PROTOCOL_SSLv2 ' ):
3265+ if has_tls_version ( 'SSLv2 ' ):
31783266 try_protocol_combo (ssl .PROTOCOL_SSLv3 , ssl .PROTOCOL_SSLv2 , False )
31793267 try_protocol_combo (ssl .PROTOCOL_SSLv3 , ssl .PROTOCOL_TLS , False ,
31803268 client_options = ssl .OP_NO_SSLv3 )
@@ -3184,41 +3272,40 @@ def test_protocol_sslv3(self):
31843272 try_protocol_combo (ssl .PROTOCOL_SSLv3 , ssl .PROTOCOL_TLS ,
31853273 False , client_options = ssl .OP_NO_SSLv2 )
31863274
3275+ @requires_tls_version ('TLSv1' )
31873276 def test_protocol_tlsv1 (self ):
31883277 """Connecting to a TLSv1 server with various client options"""
31893278 if support .verbose :
31903279 sys .stdout .write ("\n " )
31913280 try_protocol_combo (ssl .PROTOCOL_TLSv1 , ssl .PROTOCOL_TLSv1 , 'TLSv1' )
31923281 try_protocol_combo (ssl .PROTOCOL_TLSv1 , ssl .PROTOCOL_TLSv1 , 'TLSv1' , ssl .CERT_OPTIONAL )
31933282 try_protocol_combo (ssl .PROTOCOL_TLSv1 , ssl .PROTOCOL_TLSv1 , 'TLSv1' , ssl .CERT_REQUIRED )
3194- if hasattr ( ssl , 'PROTOCOL_SSLv2 ' ):
3283+ if has_tls_version ( 'SSLv2 ' ):
31953284 try_protocol_combo (ssl .PROTOCOL_TLSv1 , ssl .PROTOCOL_SSLv2 , False )
3196- if hasattr ( ssl , 'PROTOCOL_SSLv3 ' ):
3285+ if has_tls_version ( 'SSLv3 ' ):
31973286 try_protocol_combo (ssl .PROTOCOL_TLSv1 , ssl .PROTOCOL_SSLv3 , False )
31983287 try_protocol_combo (ssl .PROTOCOL_TLSv1 , ssl .PROTOCOL_TLS , False ,
31993288 client_options = ssl .OP_NO_TLSv1 )
32003289
3201- @unittest .skipUnless (hasattr (ssl , "PROTOCOL_TLSv1_1" ),
3202- "TLS version 1.1 not supported." )
3290+ @requires_tls_version ('TLSv1_1' )
32033291 def test_protocol_tlsv1_1 (self ):
32043292 """Connecting to a TLSv1.1 server with various client options.
32053293 Testing against older TLS versions."""
32063294 if support .verbose :
32073295 sys .stdout .write ("\n " )
32083296 try_protocol_combo (ssl .PROTOCOL_TLSv1_1 , ssl .PROTOCOL_TLSv1_1 , 'TLSv1.1' )
3209- if hasattr ( ssl , 'PROTOCOL_SSLv2 ' ):
3297+ if has_tls_version ( 'SSLv2 ' ):
32103298 try_protocol_combo (ssl .PROTOCOL_TLSv1_1 , ssl .PROTOCOL_SSLv2 , False )
3211- if hasattr ( ssl , 'PROTOCOL_SSLv3 ' ):
3299+ if has_tls_version ( 'SSLv3 ' ):
32123300 try_protocol_combo (ssl .PROTOCOL_TLSv1_1 , ssl .PROTOCOL_SSLv3 , False )
32133301 try_protocol_combo (ssl .PROTOCOL_TLSv1_1 , ssl .PROTOCOL_TLS , False ,
32143302 client_options = ssl .OP_NO_TLSv1_1 )
32153303
32163304 try_protocol_combo (ssl .PROTOCOL_TLS , ssl .PROTOCOL_TLSv1_1 , 'TLSv1.1' )
3217- try_protocol_combo (ssl .PROTOCOL_TLSv1_1 , ssl .PROTOCOL_TLSv1 , False )
3218- try_protocol_combo (ssl .PROTOCOL_TLSv1 , ssl .PROTOCOL_TLSv1_1 , False )
3305+ try_protocol_combo (ssl .PROTOCOL_TLSv1_1 , ssl .PROTOCOL_TLSv1_2 , False )
3306+ try_protocol_combo (ssl .PROTOCOL_TLSv1_2 , ssl .PROTOCOL_TLSv1_1 , False )
32193307
3220- @unittest .skipUnless (hasattr (ssl , "PROTOCOL_TLSv1_2" ),
3221- "TLS version 1.2 not supported." )
3308+ @requires_tls_version ('TLSv1_2' )
32223309 def test_protocol_tlsv1_2 (self ):
32233310 """Connecting to a TLSv1.2 server with various client options.
32243311 Testing against older TLS versions."""
@@ -3227,9 +3314,9 @@ def test_protocol_tlsv1_2(self):
32273314 try_protocol_combo (ssl .PROTOCOL_TLSv1_2 , ssl .PROTOCOL_TLSv1_2 , 'TLSv1.2' ,
32283315 server_options = ssl .OP_NO_SSLv3 | ssl .OP_NO_SSLv2 ,
32293316 client_options = ssl .OP_NO_SSLv3 | ssl .OP_NO_SSLv2 ,)
3230- if hasattr ( ssl , 'PROTOCOL_SSLv2 ' ):
3317+ if has_tls_version ( 'SSLv2 ' ):
32313318 try_protocol_combo (ssl .PROTOCOL_TLSv1_2 , ssl .PROTOCOL_SSLv2 , False )
3232- if hasattr ( ssl , 'PROTOCOL_SSLv3 ' ):
3319+ if has_tls_version ( 'SSLv3 ' ):
32333320 try_protocol_combo (ssl .PROTOCOL_TLSv1_2 , ssl .PROTOCOL_SSLv3 , False )
32343321 try_protocol_combo (ssl .PROTOCOL_TLSv1_2 , ssl .PROTOCOL_TLS , False ,
32353322 client_options = ssl .OP_NO_TLSv1_2 )
@@ -3672,7 +3759,7 @@ def test_version_basic(self):
36723759 self .assertIs (s .version (), None )
36733760 self .assertIs (s ._sslobj , None )
36743761 s .connect ((HOST , server .port ))
3675- if IS_OPENSSL_1_1_1 and ssl . HAS_TLSv1_3 :
3762+ if IS_OPENSSL_1_1_1 and has_tls_version ( 'TLSv1_3' ) :
36763763 self .assertEqual (s .version (), 'TLSv1.3' )
36773764 elif ssl .OPENSSL_VERSION_INFO >= (1 , 0 , 2 ):
36783765 self .assertEqual (s .version (), 'TLSv1.2' )
@@ -3681,8 +3768,7 @@ def test_version_basic(self):
36813768 self .assertIs (s ._sslobj , None )
36823769 self .assertIs (s .version (), None )
36833770
3684- @unittest .skipUnless (ssl .HAS_TLSv1_3 ,
3685- "test requires TLSv1.3 enabled OpenSSL" )
3771+ @requires_tls_version ('TLSv1_3' )
36863772 def test_tls1_3 (self ):
36873773 context = ssl .SSLContext (ssl .PROTOCOL_TLS )
36883774 context .load_cert_chain (CERTFILE )
@@ -3699,9 +3785,9 @@ def test_tls1_3(self):
36993785 })
37003786 self .assertEqual (s .version (), 'TLSv1.3' )
37013787
3702- @unittest . skipUnless ( hasattr ( ssl . SSLContext , 'minimum_version' ),
3703- "required OpenSSL 1.1.0g" )
3704- def test_min_max_version (self ):
3788+ @requires_minimum_version
3789+ @ requires_tls_version ( 'TLSv1_2' )
3790+ def test_min_max_version_tlsv1_2 (self ):
37053791 client_context , server_context , hostname = testing_context ()
37063792 # client TLSv1.0 to 1.2
37073793 client_context .minimum_version = ssl .TLSVersion .TLSv1
@@ -3716,7 +3802,13 @@ def test_min_max_version(self):
37163802 s .connect ((HOST , server .port ))
37173803 self .assertEqual (s .version (), 'TLSv1.2' )
37183804
3805+ @requires_minimum_version
3806+ @requires_tls_version ('TLSv1_1' )
3807+ def test_min_max_version_tlsv1_1 (self ):
3808+ client_context , server_context , hostname = testing_context ()
37193809 # client 1.0 to 1.2, server 1.0 to 1.1
3810+ client_context .minimum_version = ssl .TLSVersion .TLSv1
3811+ client_context .maximum_version = ssl .TLSVersion .TLSv1_2
37203812 server_context .minimum_version = ssl .TLSVersion .TLSv1
37213813 server_context .maximum_version = ssl .TLSVersion .TLSv1_1
37223814
@@ -3726,6 +3818,10 @@ def test_min_max_version(self):
37263818 s .connect ((HOST , server .port ))
37273819 self .assertEqual (s .version (), 'TLSv1.1' )
37283820
3821+ @requires_minimum_version
3822+ @requires_tls_version ('TLSv1_2' )
3823+ def test_min_max_version_mismatch (self ):
3824+ client_context , server_context , hostname = testing_context ()
37293825 # client 1.0, server 1.2 (mismatch)
37303826 server_context .maximum_version = ssl .TLSVersion .TLSv1_2
37313827 server_context .minimum_version = ssl .TLSVersion .TLSv1_2
@@ -3738,10 +3834,8 @@ def test_min_max_version(self):
37383834 s .connect ((HOST , server .port ))
37393835 self .assertIn ("alert" , str (e .exception ))
37403836
3741-
3742- @unittest .skipUnless (hasattr (ssl .SSLContext , 'minimum_version' ),
3743- "required OpenSSL 1.1.0g" )
3744- @unittest .skipUnless (ssl .HAS_SSLv3 , "requires SSLv3 support" )
3837+ @requires_minimum_version
3838+ @requires_tls_version ('SSLv3' )
37453839 def test_min_max_version_sslv3 (self ):
37463840 client_context , server_context , hostname = testing_context ()
37473841 server_context .minimum_version = ssl .TLSVersion .SSLv3
@@ -4264,7 +4358,7 @@ def test_session_handling(self):
42644358 'Session refers to a different SSLContext.' )
42654359
42664360
4267- @unittest .skipUnless (ssl . HAS_TLSv1_3 , "Test needs TLS 1.3" )
4361+ @unittest .skipUnless (has_tls_version ( 'TLSv1_3' ) , "Test needs TLS 1.3" )
42684362class TestPostHandshakeAuth (unittest .TestCase ):
42694363 def test_pha_setter (self ):
42704364 protocols = [
0 commit comments