|
39 | 39 | log = logging.getLogger(__name__) |
40 | 40 |
|
41 | 41 |
|
| 42 | +def _check_pyopenssl(): |
| 43 | + if not _HAS_SSL: |
| 44 | + raise ImportError( |
| 45 | + str(import_exception) + |
| 46 | + ', pyOpenSSL must be installed to enable SSL support with the Twisted event loop' |
| 47 | + ) |
| 48 | + |
| 49 | + |
| 50 | +def _build_pyopenssl_context_from_options(ssl_options): |
| 51 | + context = SSL.Context(ssl_options.get("ssl_version", SSL.TLSv1_METHOD)) |
| 52 | + if "certfile" in ssl_options: |
| 53 | + context.use_certificate_file(ssl_options["certfile"]) |
| 54 | + if "keyfile" in ssl_options: |
| 55 | + context.use_privatekey_file(ssl_options["keyfile"]) |
| 56 | + if "ca_certs" in ssl_options: |
| 57 | + context.load_verify_locations(ssl_options["ca_certs"]) |
| 58 | + if "cert_reqs" in ssl_options: |
| 59 | + context.set_verify( |
| 60 | + ssl_options["cert_reqs"], |
| 61 | + callback=lambda _connection, _x509, _errnum, _errdepth, ok: ok |
| 62 | + ) |
| 63 | + return context |
| 64 | + |
| 65 | + |
42 | 66 | def _cleanup(cleanup_weakref): |
43 | 67 | try: |
44 | 68 | cleanup_weakref()._cleanup() |
@@ -141,25 +165,14 @@ def _on_loop_timer(self): |
141 | 165 | class _SSLCreator(object): |
142 | 166 | def __init__(self, endpoint, ssl_context, ssl_options, check_hostname, timeout): |
143 | 167 | self.endpoint = endpoint |
144 | | - self.ssl_options = ssl_options |
| 168 | + self.ssl_options = ssl_options or {} |
145 | 169 | self.check_hostname = check_hostname |
146 | 170 | self.timeout = timeout |
147 | 171 |
|
148 | | - if ssl_context: |
| 172 | + if ssl_context is not None: |
149 | 173 | self.context = ssl_context |
150 | 174 | else: |
151 | | - self.context = SSL.Context(SSL.TLSv1_METHOD) |
152 | | - if "certfile" in self.ssl_options: |
153 | | - self.context.use_certificate_file(self.ssl_options["certfile"]) |
154 | | - if "keyfile" in self.ssl_options: |
155 | | - self.context.use_privatekey_file(self.ssl_options["keyfile"]) |
156 | | - if "ca_certs" in self.ssl_options: |
157 | | - self.context.load_verify_locations(self.ssl_options["ca_certs"]) |
158 | | - if "cert_reqs" in self.ssl_options: |
159 | | - self.context.set_verify( |
160 | | - self.ssl_options["cert_reqs"], |
161 | | - callback=self.verify_callback |
162 | | - ) |
| 175 | + self.context = _build_pyopenssl_context_from_options(self.ssl_options) |
163 | 176 | self.context.set_info_callback(self.info_callback) |
164 | 177 |
|
165 | 178 | def verify_callback(self, connection, x509, errnum, errdepth, ok): |
@@ -217,27 +230,27 @@ def __init__(self, *args, **kwargs): |
217 | 230 | self._loop.maybe_start() |
218 | 231 |
|
219 | 232 | def _check_pyopenssl(self): |
220 | | - if self.ssl_context or self.ssl_options: |
221 | | - if not _HAS_SSL: |
222 | | - raise ImportError( |
223 | | - str(import_exception) + |
224 | | - ', pyOpenSSL must be installed to enable SSL support with the Twisted event loop' |
225 | | - ) |
| 233 | + if self._ssl_enabled: |
| 234 | + _check_pyopenssl() |
| 235 | + |
| 236 | + def _build_ssl_context_from_options(self): |
| 237 | + _check_pyopenssl() |
| 238 | + return _build_pyopenssl_context_from_options(self.ssl_options) |
226 | 239 |
|
227 | 240 | def add_connection(self): |
228 | 241 | """ |
229 | 242 | Convenience function to connect and store the resulting |
230 | 243 | connector. |
231 | 244 | """ |
232 | 245 | host, port = self.endpoint.resolve() |
233 | | - if self.ssl_context or self.ssl_options: |
| 246 | + if self._ssl_enabled: |
234 | 247 | # Can't use optionsForClientTLS here because it *forces* hostname verification. |
235 | 248 | # Cool they enforce strong security, but we have to be able to turn it off |
236 | 249 | self._check_pyopenssl() |
237 | 250 |
|
238 | 251 | ssl_connection_creator = _SSLCreator( |
239 | 252 | self.endpoint, |
240 | | - self.ssl_context if self.ssl_context else None, |
| 253 | + self.ssl_context if self.ssl_context is not None else None, |
241 | 254 | self.ssl_options, |
242 | 255 | self._check_hostname, |
243 | 256 | self.connect_timeout, |
|
0 commit comments