1717log = logging .getLogger (__name__ )
1818
1919
20+ DEFAULT_SSL_CIPHERS = (
21+ "ECDHE-RSA-AES256-GCM-SHA384" ,
22+ "ECDHE-ECDSA-AES256-GCM-SHA384" ,
23+ "ECDHE-RSA-CHACHA20-POLY1305" ,
24+ "ECDHE-ECDSA-CHACHA20-POLY1305" ,
25+ "ECDHE-RSA-AES128-GCM-SHA256" ,
26+ "ECDHE-ECDSA-AES128-GCM-SHA256" ,
27+ )
28+
29+ DEFAULT_SSL_MIN_VERSION = ssl .TLSVersion .TLSv1_3
30+ DEFAULT_SSL_MAX_VERSION = ssl .TLSVersion .TLSv1_3
31+
32+
2033@dataclass (frozen = True )
2134class SSLOptionsBase :
2235 cert : Optional [Path ]
@@ -25,13 +38,19 @@ class SSLOptionsBase:
2538 verify : bool
2639 require_client_cert : bool
2740 purpose : ssl .Purpose
41+ minimum_version : ssl .TLSVersion = DEFAULT_SSL_MIN_VERSION
42+ maximum_version : ssl .TLSVersion = DEFAULT_SSL_MAX_VERSION
43+ ciphers : Tuple [str , ...] = DEFAULT_SSL_CIPHERS
2844
2945
3046class SSLOptions (SSLOptionsBase ):
3147 def __init__ (
3248 self , cert : Optional [PathOrStr ], key : Optional [PathOrStr ],
3349 ca : Optional [PathOrStr ], verify : bool , require_client_cert : bool ,
3450 purpose : ssl .Purpose ,
51+ minimum_version : ssl .TLSVersion = DEFAULT_SSL_MIN_VERSION ,
52+ maximum_version : ssl .TLSVersion = DEFAULT_SSL_MAX_VERSION ,
53+ ciphers : Tuple [str , ...] = DEFAULT_SSL_CIPHERS ,
3554 ) -> None :
3655 super ().__init__ (
3756 cert = Path (cert ) if cert else None ,
@@ -40,25 +59,48 @@ def __init__(
4059 verify = verify ,
4160 require_client_cert = require_client_cert ,
4261 purpose = purpose ,
62+ minimum_version = minimum_version ,
63+ maximum_version = maximum_version ,
64+ ciphers = ciphers ,
4365 )
4466
4567 def create_context (self ) -> ssl .SSLContext :
4668 context = ssl .create_default_context (
47- purpose = self .purpose , cafile = self . ca ,
69+ purpose = self .purpose ,
4870 )
4971
50- if self .ca and not self .ca .exists ():
51- raise FileNotFoundError ("CA file doesn't exists" )
72+ # Disable compression to prevent CRIME attacks
73+ context .options |= ssl .OP_NO_COMPRESSION
74+
75+ context .maximum_version = self .maximum_version
76+ context .minimum_version = self .minimum_version
77+ context .set_ciphers (":" .join (self .ciphers ))
78+
79+ if not self .verify :
80+ context .check_hostname = False
81+
82+ if self .ca :
83+ log .debug ("Loading CA from %s" , self .ca )
84+ if not self .ca .exists ():
85+ raise FileNotFoundError (
86+ "CA file doesn't exists" , str (self .ca .resolve ()),
87+ )
88+ context .load_verify_locations (cafile = str (self .ca ))
5289
5390 if self .require_client_cert :
91+ log .debug ("Set server-side cert verification" )
5492 context .verify_mode = ssl .VerifyMode .CERT_REQUIRED
93+ # Post-handshake authentication is required
94+ context .post_handshake_auth = True
95+ else :
96+ # Disable server-side cert verification
97+ context .check_hostname = False
98+ context .verify_mode = ssl .VerifyMode .CERT_NONE
5599
100+ # Load server-side cert and key
56101 if self .key and self .cert :
57102 context .load_cert_chain (self .cert , self .key )
58103
59- if not self .verify :
60- context .check_hostname = False
61-
62104 return context
63105
64106
@@ -69,13 +111,20 @@ def __init__(
69111 self , * , address : Optional [str ] = None , port : Optional [int ] = None ,
70112 cert : PathOrStr , key : PathOrStr , ca : Optional [PathOrStr ] = None ,
71113 require_client_cert : bool = False , verify : bool = True ,
114+ minimum_version : ssl .TLSVersion = DEFAULT_SSL_MIN_VERSION ,
115+ maximum_version : ssl .TLSVersion = DEFAULT_SSL_MAX_VERSION ,
116+ ciphers : Tuple [str , ...] = DEFAULT_SSL_CIPHERS ,
72117 options : OptionsType = (), sock : Optional [socket .socket ] = None ,
73118 ** kwargs : Any ,
74119 ):
75120
76121 self .__ssl_options = SSLOptions (
77- cert , key , ca , verify , require_client_cert ,
78- ssl .Purpose .CLIENT_AUTH ,
122+ cert = cert , key = key , ca = ca , verify = verify ,
123+ require_client_cert = require_client_cert ,
124+ purpose = ssl .Purpose .CLIENT_AUTH ,
125+ minimum_version = minimum_version ,
126+ maximum_version = maximum_version ,
127+ ciphers = ciphers ,
79128 )
80129
81130 if not sock :
0 commit comments