def secure(self, verify=True, hostname=None): """ Apply a layer of security onto this connection. """ from ssl import SSLContext, SSLError try: # noinspection PyUnresolvedReferences from ssl import PROTOCOL_TLS except ImportError: from ssl import PROTOCOL_SSLv23 context = SSLContext(PROTOCOL_SSLv23) else: context = SSLContext(PROTOCOL_TLS) if verify: from ssl import CERT_REQUIRED context.verify_mode = CERT_REQUIRED context.check_hostname = bool(hostname) else: from ssl import CERT_NONE context.verify_mode = CERT_NONE context.load_default_certs() try: self.__socket = context.wrap_socket(self.__socket, server_hostname=hostname) except (IOError, OSError) as error: # TODO: add connection failure/diagnostic callback if error.errno == 0: raise BrokenWireError( "Peer closed connection during TLS handshake; " "server may not be configured for secure connections") else: raise WireError( "Unable to establish secure connection with remote peer") else: self.__active_time = monotonic()
def create_urllib3_context(ssl_version=None, cert_reqs=None, options=None, ciphers=None): """All arguments have the same meaning as ``ssl_wrap_socket``. By default, this function does a lot of the same work that ``ssl.create_default_context`` does on Python 3.4+. It: - Disables SSLv2, SSLv3, and compression - Sets a restricted set of server ciphers If you wish to enable SSLv3, you can do:: from urllib3.util import ssl_ context = ssl_.create_urllib3_context() context.options &= ~ssl_.OP_NO_SSLv3 You can do the same to enable compression (substituting ``COMPRESSION`` for ``SSLv3`` in the last line above). :param ssl_version: The desired protocol version to use. This will default to PROTOCOL_SSLv23 which will negotiate the highest protocol that both the server and your installation of OpenSSL support. :param cert_reqs: Whether to require the certificate verification. This defaults to ``ssl.CERT_REQUIRED``. :param options: Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``, ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``. :param ciphers: Which cipher suites to allow the server to select. :returns: Constructed SSLContext object with specified options :rtype: SSLContext """ context = SSLContext(ssl_version or ssl.PROTOCOL_SSLv23) context.set_ciphers(ciphers or DEFAULT_CIPHERS) # Setting the default here, as we may have no ssl module on import cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs if options is None: options = 0 # SSLv2 is easily broken and is considered harmful and dangerous options |= OP_NO_SSLv2 # SSLv3 has several problems and is now dangerous options |= OP_NO_SSLv3 # Disable compression to prevent CRIME attacks for OpenSSL 1.0+ # (issue #309) options |= OP_NO_COMPRESSION context.options |= options context.verify_mode = cert_reqs if getattr(context, 'check_hostname', None) is not None: # Platform-specific: Python 3.2 # We do our own verification, including fingerprints and alternative # hostnames. So disable it here context.check_hostname = False return context
def create_urllib3_context(ssl_version=None, cert_reqs=None, options=None, ciphers=None): """All arguments have the same meaning as ``ssl_wrap_socket``. By default, this function does a lot of the same work that ``ssl.create_default_context`` does on Python 3.4+. It: - Disables SSLv2, SSLv3, and compression - Sets a restricted set of server ciphers If you wish to enable SSLv3, you can do:: from pip._vendor.urllib3.util import ssl_ context = ssl_.create_urllib3_context() context.options &= ~ssl_.OP_NO_SSLv3 You can do the same to enable compression (substituting ``COMPRESSION`` for ``SSLv3`` in the last line above). :param ssl_version: The desired protocol version to use. This will default to PROTOCOL_SSLv23 which will negotiate the highest protocol that both the server and your installation of OpenSSL support. :param cert_reqs: Whether to require the certificate verification. This defaults to ``ssl.CERT_REQUIRED``. :param options: Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``, ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``. :param ciphers: Which cipher suites to allow the server to select. :returns: Constructed SSLContext object with specified options :rtype: SSLContext """ context = SSLContext(ssl_version or ssl.PROTOCOL_SSLv23) context.set_ciphers(ciphers or DEFAULT_CIPHERS) # Setting the default here, as we may have no ssl module on import cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs if options is None: options = 0 # SSLv2 is easily broken and is considered harmful and dangerous options |= OP_NO_SSLv2 # SSLv3 has several problems and is now dangerous options |= OP_NO_SSLv3 # Disable compression to prevent CRIME attacks for OpenSSL 1.0+ # (issue #309) options |= OP_NO_COMPRESSION context.options |= options context.verify_mode = cert_reqs if getattr(context, 'check_hostname', None) is not None: # Platform-specific: Python 3.2 # We do our own verification, including fingerprints and alternative # hostnames. So disable it here context.check_hostname = False return context
async def _connect(self, urlparsed: ParseResult, verify: bool, ssl_context: SSLContext, http2: bool): """Get reader and writer.""" key = '%s-%s' % (urlparsed.hostname, urlparsed.port) if self.writer: # python 3.6 doesn't have writer.is_closing is_closing = getattr( self.writer, 'is_closing', self.writer._transport.is_closing) # type: ignore else: def is_closing(): return True # noqa if not (self.key and key == self.key and not is_closing()): if self.writer: self.writer.close() if urlparsed.scheme == 'https': ssl_context = ssl_context or ssl.create_default_context( ssl.Purpose.SERVER_AUTH, ) if http2: # flag will be removed when fully http2 support ssl_context.set_alpn_protocols(['h2', 'http/1.1']) if not verify: ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_NONE port = urlparsed.port or (443 if urlparsed.scheme == 'https' else 80) self.reader, self.writer = await asyncio.open_connection( urlparsed.hostname, port, ssl=ssl_context) self.temp_key = key await self._connection_made()
def __get_ssl_context(cls, sslca=None): """Make an SSLConext for this Python version using public or sslca """ if ((version_info[0] == 2 and (version_info[1] >= 7 and version_info[2] >= 5)) or (version_info[0] == 3 and version_info[1] >= 4)): logger.debug('SSL method for 2.7.5+ / 3.4+') # pylint: disable=no-name-in-module,import-outside-toplevel from ssl import SSLContext, PROTOCOL_TLSv1_2, CERT_REQUIRED, OP_NO_COMPRESSION ctx = SSLContext(PROTOCOL_TLSv1_2) ctx.set_ciphers('HIGH:!SSLv3:!TLSv1:!aNULL:@STRENGTH') # see CRIME security exploit ctx.options |= OP_NO_COMPRESSION # the following options are used to verify the identity of the broker if sslca: ctx.load_verify_locations(sslca) ctx.verify_mode = CERT_REQUIRED ctx.check_hostname = False else: # Verify public certifcates if sslca is None (default) from ssl import Purpose # pylint: disable=no-name-in-module,import-outside-toplevel ctx.load_default_certs(purpose=Purpose.SERVER_AUTH) ctx.verify_mode = CERT_REQUIRED ctx.check_hostname = True elif version_info[0] == 3 and version_info[1] < 4: logger.debug('Using SSL method for 3.2+, < 3.4') # pylint: disable=no-name-in-module,import-outside-toplevel from ssl import SSLContext, CERT_REQUIRED, PROTOCOL_SSLv23, OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_TLSv1 ctx = SSLContext(PROTOCOL_SSLv23) ctx.options |= (OP_NO_SSLv2 | OP_NO_SSLv3 | OP_NO_TLSv1) ctx.set_ciphers('HIGH:!SSLv3:!TLSv1:!aNULL:@STRENGTH') # the following options are used to verify the identity of the broker if sslca: ctx.load_verify_locations(sslca) ctx.verify_mode = CERT_REQUIRED else: # Verify public certifcates if sslca is None (default) ctx.set_default_verify_paths() ctx.verify_mode = CERT_REQUIRED else: raise Exception("Unsupported Python version %s" % '.'.join(str(item) for item in version_info[:3])) return ctx
def __get_ssl_context(cls, sslca=None): """Make an SSLConext for this Python version using public or sslca """ if ((version_info[0] == 2 and (version_info[1] >= 7 and version_info[2] >= 9)) or (version_info[0] == 3 and version_info[1] >= 4)): logger.debug('SSL method for 2.7.9+ / 3.4+') # pylint: disable=no-name-in-module from ssl import SSLContext, PROTOCOL_TLSv1_2, CERT_REQUIRED, OP_NO_COMPRESSION ctx = SSLContext(PROTOCOL_TLSv1_2) ctx.set_ciphers('HIGH:!SSLv3:!TLSv1:!aNULL:@STRENGTH') # see CRIME security exploit ctx.options |= OP_NO_COMPRESSION # the following options are used to verify the identity of the broker if sslca: ctx.load_verify_locations(sslca) ctx.verify_mode = CERT_REQUIRED ctx.check_hostname = False else: # Verify public certifcates if sslca is None (default) from ssl import Purpose # pylint: disable=no-name-in-module ctx.load_default_certs(purpose=Purpose.SERVER_AUTH) ctx.verify_mode = CERT_REQUIRED ctx.check_hostname = True elif version_info[0] == 3 and version_info[1] < 4: logger.debug('Using SSL method for 3.2+, < 3.4') # pylint: disable=no-name-in-module from ssl import SSLContext, CERT_REQUIRED, PROTOCOL_SSLv23, OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_TLSv1 ctx = SSLContext(PROTOCOL_SSLv23) ctx.options |= (OP_NO_SSLv2 | OP_NO_SSLv3 | OP_NO_TLSv1) ctx.set_ciphers('HIGH:!SSLv3:!TLSv1:!aNULL:@STRENGTH') # the following options are used to verify the identity of the broker if sslca: ctx.load_verify_locations(sslca) ctx.verify_mode = CERT_REQUIRED else: # Verify public certifcates if sslca is None (default) ctx.set_default_verify_paths() ctx.verify_mode = CERT_REQUIRED else: raise Exception("Unsupported Python version %s" % '.'.join(str(item) for item in version_info[:3])) return ctx
def context(self) -> Optional[SSLContext]: if self.ssl: self.logger.info("Setting up SSL") context = SSLContext(PROTOCOL_TLS) if self.cert and self.key: self.logger.info("Using SSL Cert: %s", self.cert) try: context.load_cert_chain(str(self.cert), str(self.key), password=self.key_password) except FileNotFoundError as e: raise FileNotFoundError( better_file_not_found_error( self.cert, self.key, purpose='ssl cert loading')) if self.warn_if_expires_before_days: self._warn_expiry_task = create_task( self.check_cert_expiry()) set_task_name(self._warn_expiry_task, 'CheckSSLCertValidity') context.verify_mode = CERT_REQUIRED if self.cert_required else CERT_NONE context.check_hostname = self.check_hostname self.logger.info('%s, Check Hostname: %s' % (context.verify_mode, context.check_hostname)) if context.verify_mode != CERT_NONE: if self.cafile or self.capath or self.cadata: locations = { 'cafile': str(self.cafile) if self.cafile else None, 'capath': str(self.capath) if self.capath else None, 'cadata': self.cadata } try: context.load_verify_locations(**locations) self.logger.info("Verifying SSL certs with: %s", locations) except FileNotFoundError: raise FileNotFoundError( better_file_not_found_error( *locations.values(), purpose='CA ssl cert validation')) else: context.load_default_certs(self.purpose) self.logger.info("Verifying SSL certs with: %s", get_default_verify_paths()) self.logger.info("SSL Context loaded") # OpenSSL 1.1.1 keylog file if hasattr(context, 'keylog_filename'): keylogfile = os.environ.get('SSLKEYLOGFILE') if keylogfile and not sys.flags.ignore_environment: self.logger.warning( "TLS encryption secrets are being stored in %s", keylogfile) context.keylog_filename = keylogfile return context return None
def load_TLS(self): context = SSLContext(PROTOCOL_TLS) context.minimum_version = TLSVersion.TLSv1_3 context.verify_mode = CERT_REQUIRED context.check_hostname = True if self.CA != 'default' and self.CA != '': context.load_verify_locations(self.CA) else: context.load_default_certs() self.server = create_connection((self.SERVER_HOST, self.SERVER_PORT)) self.server = context.wrap_socket(self.server, server_hostname=self.SERVER_HOST)
def __init__(self): user = os.getenv("PG_USER", 'postgres') password = os.getenv("PG_PASSWORD", None) self._database = os.getenv("PG_DATABASE", 'postgres') host = os.getenv("PG_HOST", 'localhost') port = int(os.getenv("PG_PORT", '5432')) ssl_context = SSLContext() ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_NONE self._con = pg8000.connect(user, host, self._database, port, password) self._con.autocommit = True self._create_schema()
async def create_redis_pool(address: str, ssl_validation: SSLValidation) -> Redis: ssl_context: Union[SSLContext, bool] if ssl_validation == SSLValidation.SELF_SIGNED: ssl_context = SSLContext(ssl.PROTOCOL_TLS_CLIENT) ssl_context.check_hostname = False ssl_context.verify_mode = ssl.VerifyMode.CERT_NONE elif ssl_validation == SSLValidation.NONE: ssl_context = False else: ssl_context = ssl.create_default_context() return await aioredis.create_redis_pool(address, ssl=ssl_context)
def create_session(url: str, port: int, context: ssl.SSLContext = ssl.create_default_context()): """ Create a secure connection to any server on any port with a defined context on a specific timeout. :param url: url of the website :param context: ssl context :param port: port :return: created secure socket """ cert_verified = True context.check_hostname = True context.verify_mode = ssl.VerifyMode.CERT_REQUIRED sleep = 0 # Loop until there is a valid response or after 15 seconds # because of rate limiting on some servers while True: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(5) # in seconds # context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) ssl_socket = context.wrap_socket(sock, server_hostname=url) try: logging.debug(f'connecting... (main connection)') ssl_socket.connect((url, port)) break except ssl.SSLCertVerificationError: cert_verified = False context.check_hostname = False context.verify_mode = ssl.CERT_NONE except socket.timeout: raise ConnectionTimeoutError() except socket.gaierror: raise DNSError() except ConnectionResetError as e: raise UnknownConnectionError(e) except socket.error as e: ssl_socket.close() sleep = incremental_sleep(sleep, e, 1) return ssl_socket, cert_verified
def create_urllib3_context(ssl_version = None, cert_reqs = None, options = None, ciphers = None): context = SSLContext(ssl_version or ssl.PROTOCOL_SSLv23) cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs if options is None: options = 0 options |= OP_NO_SSLv2 options |= OP_NO_SSLv3 options |= OP_NO_COMPRESSION context.options |= options if getattr(context, 'supports_set_ciphers', True): context.set_ciphers(ciphers or DEFAULT_CIPHERS) context.verify_mode = cert_reqs if getattr(context, 'check_hostname', None) is not None: context.check_hostname = False return context
async def connect(self) -> bool: try: context = SSLContext(PROTOCOL_TLSv1) context.verify_mode = CERT_NONE context.check_hostname = False LOGGER.debug('Connecting to %s', self._url) self._connection = await ws_connect(self._url, ssl=context) except InvalidURI as error: raise WebSocketTransportError(f'Wrong uri: {error}') except Exception as error: raise WebSocketTransportError(f'Unknown error: {error}') await self._handshake() return True
def _get_connector(verify_host_certificate: bool, client_key: Optional[Path], client_cert: Optional[Path]) -> TCPConnector: """Return an aiohttp ClientSession based on the options.""" ssl_context = SSLContext() if not verify_host_certificate: ssl_context.check_hostname = False ssl_context.verify_mode = CERT_NONE cert = client_cert key = client_key if cert is not None: ssl_context.load_cert_chain(cert, key) return TCPConnector(ssl=ssl_context)
def secure(self, verify=True, hostname=None): """ Apply a layer of security onto this connection. """ from ssl import SSLContext, PROTOCOL_TLS, CERT_NONE, CERT_REQUIRED context = SSLContext(PROTOCOL_TLS) if verify: context.verify_mode = CERT_REQUIRED context.check_hostname = bool(hostname) else: context.verify_mode = CERT_NONE context.load_default_certs() try: self.__socket = context.wrap_socket(self.__socket, server_hostname=hostname) except (IOError, OSError): # TODO: add connection failure/diagnostic callback raise WireError( "Unable to establish secure connection with remote peer")
def get_session(self): """Return an aiohttp ClientSession based on the options.""" ssl_context = SSLContext() if not self.verify_host_certificate: ssl_context.check_hostname = False ssl_context.verify_mode = CERT_NONE cert = self.client_cert key = self.client_key if cert is not None: ssl_context.load_cert_chain(cert, key) connector = TCPConnector(ssl=ssl_context) session = ClientSession(connector=connector, ) return session
async def _connect(self, urlparsed: ParseResult, verify: bool, ssl_context: SSLContext, dns_info, http2: bool) -> None: """Get reader and writer.""" if not urlparsed.hostname: raise HttpParsingError('missing hostname') key = f'{urlparsed.hostname}-{urlparsed.port}' if self.writer: # python 3.6 doesn't have writer.is_closing is_closing = getattr( self.writer, 'is_closing', self.writer._transport.is_closing) # type: ignore else: def is_closing(): return True # noqa dns_info_copy = dns_info.copy() dns_info_copy['server_hostname'] = dns_info_copy.pop('hostname') if not (self.key and key == self.key and not is_closing()): self.close() if urlparsed.scheme == 'https': ssl_context = ssl_context or ssl.create_default_context( ssl.Purpose.SERVER_AUTH, ) # flag will be removed when fully http2 support if http2: # pragma: no cover ssl_context.set_alpn_protocols(['h2', 'http/1.1']) if not verify: ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_NONE else: del dns_info_copy['server_hostname'] port = urlparsed.port or (443 if urlparsed.scheme == 'https' else 80) dns_info_copy['port'] = port self.reader, self.writer = await open_connection( **dns_info_copy, ssl=ssl_context) self.temp_key = key await self._connection_made()
def main(): ip = 'github.com' ssl_domains = [] #context = ssl.create_default_context() context = SSLContext() context.verify_mode = CERT_REQUIRED context.check_hostname = False context.load_verify_locations("./cacert.pem") conn = context.wrap_socket(socket.socket(socket.AF_INET), server_hostname=ip) conn.connect((ip, 443)) cert = conn.getpeercert() tlen = len(cert['subject']) ssl_domains.append(cert['subject'][tlen - 1][0][1]) if cert['subjectAltName']: tmp_domains = cert['subjectAltName'] for item in tmp_domains: if item[1] not in ssl_domains: ssl_domains.append(item[1]) print(ssl_domains)
def open_url(url, data=None, headers=None, method=None, use_proxy=True, force=False, last_mod_time=None, timeout=10, validate_certs=True, url_username=None, url_password=None, http_agent=None, force_basic_auth=False, follow_redirects='urllib2', client_cert=None, client_key=None, cookies=None): ''' Sends a request via HTTP(S) or FTP using urllib2 (Python2) or urllib (Python3) Does not require the module environment ''' handlers = [] ssl_handler = maybe_add_ssl_handler(url, validate_certs) if ssl_handler: handlers.append(ssl_handler) # FIXME: change the following to use the generic_urlparse function # to remove the indexed references for 'parsed' parsed = urlparse(url) if parsed[0] != 'ftp': username = url_username if headers is None: headers = {} if username: password = url_password netloc = parsed[1] elif '@' in parsed[1]: credentials, netloc = parsed[1].split('@', 1) if ':' in credentials: username, password = credentials.split(':', 1) else: username = credentials password = '' parsed = list(parsed) parsed[1] = netloc # reconstruct url without credentials url = urlunparse(parsed) if username and not force_basic_auth: passman = urllib_request.HTTPPasswordMgrWithDefaultRealm() # this creates a password manager passman.add_password(None, netloc, username, password) # because we have put None at the start it will always # use this username/password combination for urls # for which `theurl` is a super-url authhandler = urllib_request.HTTPBasicAuthHandler(passman) digest_authhandler = urllib_request.HTTPDigestAuthHandler(passman) # create the AuthHandler handlers.append(authhandler) handlers.append(digest_authhandler) elif username and force_basic_auth: headers["Authorization"] = basic_auth_header(username, password) else: try: rc = netrc.netrc(os.environ.get('NETRC')) login = rc.authenticators(parsed[1]) except IOError: login = None if login: username, _, password = login if username and password: headers["Authorization"] = basic_auth_header( username, password) if not use_proxy: proxyhandler = urllib_request.ProxyHandler({}) handlers.append(proxyhandler) if HAS_SSLCONTEXT and not validate_certs: # In 2.7.9, the default context validates certificates context = SSLContext(ssl.PROTOCOL_SSLv23) context.options |= ssl.OP_NO_SSLv2 context.options |= ssl.OP_NO_SSLv3 context.verify_mode = ssl.CERT_NONE context.check_hostname = False handlers.append( HTTPSClientAuthHandler(client_cert=client_cert, client_key=client_key, context=context)) elif client_cert: handlers.append( HTTPSClientAuthHandler(client_cert=client_cert, client_key=client_key)) # pre-2.6 versions of python cannot use the custom https # handler, since the socket class is lacking create_connection. # Some python builds lack HTTPS support. if hasattr(socket, 'create_connection') and CustomHTTPSHandler: handlers.append(CustomHTTPSHandler) handlers.append(RedirectHandlerFactory(follow_redirects, validate_certs)) # add some nicer cookie handling if cookies is not None: handlers.append(urllib_request.HTTPCookieProcessor(cookies)) opener = urllib_request.build_opener(*handlers) urllib_request.install_opener(opener) data = to_bytes(data, nonstring='passthru') if method: if method.upper() not in ('OPTIONS', 'GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'TRACE', 'CONNECT', 'PATCH'): raise ConnectionError('invalid HTTP request method; %s' % method.upper()) request = RequestWithMethod(url, method.upper(), data) else: request = urllib_request.Request(url, data) # add the custom agent header, to help prevent issues # with sites that block the default urllib agent string if http_agent: request.add_header('User-agent', http_agent) # Cache control # Either we directly force a cache refresh if force: request.add_header('cache-control', 'no-cache') # or we do it if the original is more recent than our copy elif last_mod_time: tstamp = last_mod_time.strftime('%a, %d %b %Y %H:%M:%S +0000') request.add_header('If-Modified-Since', tstamp) # user defined headers now, which may override things we've set above if headers: if not isinstance(headers, dict): raise ValueError("headers provided to fetch_url() must be a dict") for header in headers: request.add_header(header, headers[header]) urlopen_args = [request, None] if sys.version_info >= (2, 6, 0): # urlopen in python prior to 2.6.0 did not # have a timeout parameter urlopen_args.append(timeout) r = urllib_request.urlopen(*urlopen_args) return r
allow_reuse_address = True def handle(self): data = self.request[0] serv = self.request[1] addr = self.client_address transfer(data, addr, serv) if __name__ == "__main__": print('init') ENV['TLS'] = SSLContext(PROTOCOL_TLS) ENV['TLS'].verify_mode = CERT_REQUIRED ENV['TLS'].check_hostname = True ENV['TLS'].load_default_certs() #tlsctx.load_verify_locations(cadata=cadata) # Cloudflare ENV['REMOTE_SERVERS'].append(('1.1.1.1', '1.1.1.1', 853)) ENV['REMOTE_SERVERS'].append(('1.0.0.1', '1.0.0.1', 853)) # Quad9 (Packet Clearing House and IBM) ENV['REMOTE_SERVERS'].append(('dns.quad9.net', '9.9.9.9', 853)) ENV['REMOTE_SERVERS'].append(('dns.quad9.net', '149.112.112.112', 853)) ENV['REMOTE_SERVERS_LENGTH'] = len(ENV['REMOTE_SERVERS']) with ThreadUDPServer((ENV['SERVER_IP'], ENV['SERVER_PORT']), ThreadUDPRequestHandler) as server: print('finished')
def get_ssl_context(*args): """Create and return an SSLContext object.""" (certfile, keyfile, passphrase, ca_certs, cert_reqs, crlfile, match_hostname) = args verify_mode = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs # Note PROTOCOL_SSLv23 is about the most misleading name imaginable. # This configures the server and client to negotiate the # highest protocol version they both support. A very good thing. # PROTOCOL_TLS_CLIENT was added in CPython 3.6, deprecating # PROTOCOL_SSLv23. ctx = SSLContext( getattr(ssl, "PROTOCOL_TLS_CLIENT", ssl.PROTOCOL_SSLv23)) # SSLContext.check_hostname was added in CPython 2.7.9 and 3.4. # PROTOCOL_TLS_CLIENT (added in Python 3.6) enables it by default. if hasattr(ctx, "check_hostname"): if _PY37PLUS and verify_mode != ssl.CERT_NONE: # Python 3.7 uses OpenSSL's hostname matching implementation # making it the obvious version to start using this with. # Python 3.6 might have been a good version, but it suffers # from https://bugs.python.org/issue32185. # We'll use our bundled match_hostname for older Python # versions, which also supports IP address matching # with Python < 3.5. ctx.check_hostname = match_hostname else: ctx.check_hostname = False if hasattr(ctx, "options"): # Explicitly disable SSLv2, SSLv3 and TLS compression. Note that # up to date versions of MongoDB 2.4 and above already disable # SSLv2 and SSLv3, python disables SSLv2 by default in >= 2.7.7 # and >= 3.3.4 and SSLv3 in >= 3.4.3. There is no way for us to do # any of this explicitly for python 2.7 before 2.7.9. ctx.options |= getattr(ssl, "OP_NO_SSLv2", 0) ctx.options |= getattr(ssl, "OP_NO_SSLv3", 0) # OpenSSL >= 1.0.0 ctx.options |= getattr(ssl, "OP_NO_COMPRESSION", 0) # Python 3.7+ with OpenSSL >= 1.1.0h ctx.options |= getattr(ssl, "OP_NO_RENEGOTIATION", 0) if certfile is not None: try: if passphrase is not None: vi = sys.version_info # Since python just added a new parameter to an existing method # this seems to be about the best we can do. if (vi[0] == 2 and vi < (2, 7, 9) or vi[0] == 3 and vi < (3, 3)): raise ConfigurationError( "Support for ssl_pem_passphrase requires " "python 2.7.9+ (pypy 2.5.1+) or 3.3+") ctx.load_cert_chain(certfile, keyfile, passphrase) else: ctx.load_cert_chain(certfile, keyfile) except ssl.SSLError as exc: raise ConfigurationError( "Private key doesn't match certificate: %s" % (exc,)) if crlfile is not None: if not hasattr(ctx, "verify_flags"): raise ConfigurationError( "Support for ssl_crlfile requires " "python 2.7.9+ (pypy 2.5.1+) or 3.4+") # Match the server's behavior. ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF ctx.load_verify_locations(crlfile) if ca_certs is not None: ctx.load_verify_locations(ca_certs) elif cert_reqs != ssl.CERT_NONE: # CPython >= 2.7.9 or >= 3.4.0, pypy >= 2.5.1 if hasattr(ctx, "load_default_certs"): ctx.load_default_certs() # Python >= 3.2.0, useless on Windows. elif (sys.platform != "win32" and hasattr(ctx, "set_default_verify_paths")): ctx.set_default_verify_paths() elif sys.platform == "win32" and HAVE_WINCERTSTORE: with _WINCERTSLOCK: if _WINCERTS is None: _load_wincerts() ctx.load_verify_locations(_WINCERTS.name) elif HAVE_CERTIFI: ctx.load_verify_locations(certifi.where()) else: raise ConfigurationError( "`ssl_cert_reqs` is not ssl.CERT_NONE and no system " "CA certificates could be loaded. `ssl_ca_certs` is " "required.") ctx.verify_mode = verify_mode return ctx
#!/usr/bin/env python3 from hermes_ui.app import app from ssl import SSLContext, PROTOCOL_TLS, CERT_REQUIRED, Purpose if __name__ == '__main__': """ Départ du serveur générique WSGI Flask """ context = None if app.config.get('HERMES_CERTIFICAT_TLS') and app.config.get( 'HERMES_CLE_PRIVEE_TLS'): context = SSLContext(PROTOCOL_TLS) context.check_hostname = True context.set_ciphers( "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384" ) context.verify_mode = CERT_REQUIRED context.load_cert_chain(app.config.get('HERMES_CERTIFICAT_TLS'), app.config.get('HERMES_CLE_PRIVEE_TLS')) context.load_default_certs(Purpose.SERVER_AUTH) if app.config.get('HERMES_CERTIFICAT_CA'): context.load_verify_locations( app.config.get('HERMES_CERTIFICAT_CA')) adhoc_request = app.config.get(
def open_url(url, data=None, headers=None, method=None, use_proxy=True, force=False, last_mod_time=None, timeout=10, validate_certs=True, url_username=None, url_password=None, http_agent=None, force_basic_auth=False): ''' Fetches a file from an HTTP/FTP server using urllib2 ''' handlers = [] # FIXME: change the following to use the generic_urlparse function # to remove the indexed references for 'parsed' parsed = urlparse.urlparse(url) if parsed[0] == 'https' and validate_certs: if not HAS_SSL: raise NoSSLError('SSL validation is not available in your version of python. You can use validate_certs=False, however this is unsafe and not recommended') # do the cert validation netloc = parsed[1] if '@' in netloc: netloc = netloc.split('@', 1)[1] if ':' in netloc: hostname, port = netloc.split(':', 1) port = int(port) else: hostname = netloc port = 443 # create the SSL validation handler and # add it to the list of handlers ssl_handler = SSLValidationHandler(hostname, port) handlers.append(ssl_handler) if parsed[0] != 'ftp': username = url_username if username: password = url_password netloc = parsed[1] elif '@' in parsed[1]: credentials, netloc = parsed[1].split('@', 1) if ':' in credentials: username, password = credentials.split(':', 1) else: username = credentials password = '' parsed = list(parsed) parsed[1] = netloc # reconstruct url without credentials url = urlparse.urlunparse(parsed) if username and not force_basic_auth: passman = urllib2.HTTPPasswordMgrWithDefaultRealm() # this creates a password manager passman.add_password(None, netloc, username, password) # because we have put None at the start it will always # use this username/password combination for urls # for which `theurl` is a super-url authhandler = urllib2.HTTPBasicAuthHandler(passman) # create the AuthHandler handlers.append(authhandler) elif username and force_basic_auth: if headers is None: headers = {} headers["Authorization"] = "Basic %s" % base64.b64encode("%s:%s" % (username, password)) if not use_proxy: proxyhandler = urllib2.ProxyHandler({}) handlers.append(proxyhandler) # pre-2.6 versions of python cannot use the custom https # handler, since the socket class is lacking create_connection. # Some python builds lack HTTPS support. if hasattr(socket, 'create_connection') and CustomHTTPSHandler: handlers.append(CustomHTTPSHandler) opener = urllib2.build_opener(*handlers) urllib2.install_opener(opener) if method: if method.upper() not in ('OPTIONS','GET','HEAD','POST','PUT','DELETE','TRACE','CONNECT','PATCH'): raise ConnectionError('invalid HTTP request method; %s' % method.upper()) request = RequestWithMethod(url, method.upper(), data) else: request = urllib2.Request(url, data) # add the custom agent header, to help prevent issues # with sites that block the default urllib agent string request.add_header('User-agent', http_agent) # if we're ok with getting a 304, set the timestamp in the # header, otherwise make sure we don't get a cached copy if last_mod_time and not force: tstamp = last_mod_time.strftime('%a, %d %b %Y %H:%M:%S +0000') request.add_header('If-Modified-Since', tstamp) else: request.add_header('cache-control', 'no-cache') # user defined headers now, which may override things we've set above if headers: if not isinstance(headers, dict): raise ValueError("headers provided to fetch_url() must be a dict") for header in headers: request.add_header(header, headers[header]) urlopen_args = [request, None] if sys.version_info >= (2,6,0): # urlopen in python prior to 2.6.0 did not # have a timeout parameter urlopen_args.append(timeout) if HAS_SSLCONTEXT and not validate_certs: # In 2.7.9, the default context validates certificates context = SSLContext(ssl.PROTOCOL_SSLv23) context.options |= ssl.OP_NO_SSLv2 context.options |= ssl.OP_NO_SSLv3 context.verify_mode = ssl.CERT_NONE context.check_hostname = False urlopen_args += (None, None, None, context) r = urllib2.urlopen(*urlopen_args) return r
def open_url(url, data=None, headers=None, method=None, use_proxy=True, force=False, last_mod_time=None, timeout=10, validate_certs=True, url_username=None, url_password=None, http_agent=None, force_basic_auth=False, follow_redirects='urllib2'): ''' Sends a request via HTTP(S) or FTP using urllib2 (Python2) or urllib (Python3) Does not require the module environment ''' handlers = [] ssl_handler = maybe_add_ssl_handler(url, validate_certs) if ssl_handler: handlers.append(ssl_handler) # FIXME: change the following to use the generic_urlparse function # to remove the indexed references for 'parsed' parsed = urlparse(url) if parsed[0] != 'ftp': username = url_username if headers is None: headers = {} if username: password = url_password netloc = parsed[1] elif '@' in parsed[1]: credentials, netloc = parsed[1].split('@', 1) if ':' in credentials: username, password = credentials.split(':', 1) else: username = credentials password = '' parsed = list(parsed) parsed[1] = netloc # reconstruct url without credentials url = urlunparse(parsed) if username and not force_basic_auth: passman = urllib_request.HTTPPasswordMgrWithDefaultRealm() # this creates a password manager passman.add_password(None, netloc, username, password) # because we have put None at the start it will always # use this username/password combination for urls # for which `theurl` is a super-url authhandler = urllib_request.HTTPBasicAuthHandler(passman) # create the AuthHandler handlers.append(authhandler) elif username and force_basic_auth: headers["Authorization"] = basic_auth_header(username, password) else: try: rc = netrc.netrc(os.environ.get('NETRC')) login = rc.authenticators(parsed[1]) except IOError: login = None if login: username, _, password = login if username and password: headers["Authorization"] = basic_auth_header(username, password) if not use_proxy: proxyhandler = urllib_request.ProxyHandler({}) handlers.append(proxyhandler) if HAS_SSLCONTEXT and not validate_certs: # In 2.7.9, the default context validates certificates context = SSLContext(ssl.PROTOCOL_SSLv23) context.options |= ssl.OP_NO_SSLv2 context.options |= ssl.OP_NO_SSLv3 context.verify_mode = ssl.CERT_NONE context.check_hostname = False handlers.append(urllib_request.HTTPSHandler(context=context)) # pre-2.6 versions of python cannot use the custom https # handler, since the socket class is lacking create_connection. # Some python builds lack HTTPS support. if hasattr(socket, 'create_connection') and CustomHTTPSHandler: handlers.append(CustomHTTPSHandler) handlers.append(RedirectHandlerFactory(follow_redirects, validate_certs)) opener = urllib_request.build_opener(*handlers) urllib_request.install_opener(opener) if method: if method.upper() not in ('OPTIONS','GET','HEAD','POST','PUT','DELETE','TRACE','CONNECT','PATCH'): raise ConnectionError('invalid HTTP request method; %s' % method.upper()) request = RequestWithMethod(url, method.upper(), data) else: request = urllib_request.Request(url, data) # add the custom agent header, to help prevent issues # with sites that block the default urllib agent string request.add_header('User-agent', http_agent) # if we're ok with getting a 304, set the timestamp in the # header, otherwise make sure we don't get a cached copy if last_mod_time and not force: tstamp = last_mod_time.strftime('%a, %d %b %Y %H:%M:%S +0000') request.add_header('If-Modified-Since', tstamp) else: request.add_header('cache-control', 'no-cache') # user defined headers now, which may override things we've set above if headers: if not isinstance(headers, dict): raise ValueError("headers provided to fetch_url() must be a dict") for header in headers: request.add_header(header, headers[header]) urlopen_args = [request, None] if sys.version_info >= (2,6,0): # urlopen in python prior to 2.6.0 did not # have a timeout parameter urlopen_args.append(timeout) r = urllib_request.urlopen(*urlopen_args) return r
def create_urllib3_context( ssl_version: Optional[int] = None, cert_reqs: Optional[int] = None, options: Optional[int] = None, ciphers: Optional[str] = None, ) -> "ssl.SSLContext": """All arguments have the same meaning as ``ssl_wrap_socket``. By default, this function does a lot of the same work that ``ssl.create_default_context`` does on Python 3.4+. It: - Disables SSLv2, SSLv3, and compression - Sets a restricted set of server ciphers If you wish to enable SSLv3, you can do:: from urllib3.util import ssl_ context = ssl_.create_urllib3_context() context.options &= ~ssl_.OP_NO_SSLv3 You can do the same to enable compression (substituting ``COMPRESSION`` for ``SSLv3`` in the last line above). :param ssl_version: The desired protocol version to use. This will default to PROTOCOL_SSLv23 which will negotiate the highest protocol that both the server and your installation of OpenSSL support. :param cert_reqs: Whether to require the certificate verification. This defaults to ``ssl.CERT_REQUIRED``. :param options: Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``, ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``, and ``ssl.OP_NO_TICKET``. :param ciphers: Which cipher suites to allow the server to select. Defaults to either system configured ciphers if OpenSSL 1.1.1+, otherwise uses a secure default set of ciphers. :returns: Constructed SSLContext object with specified options :rtype: SSLContext """ if SSLContext is None: raise TypeError( "Can't create an SSLContext object without an ssl module") context = SSLContext(ssl_version or PROTOCOL_TLS) # Unless we're given ciphers defer to either system ciphers in # the case of OpenSSL 1.1.1+ or use our own secure default ciphers. if ciphers is not None or not USE_DEFAULT_SSLCONTEXT_CIPHERS: context.set_ciphers(ciphers or DEFAULT_CIPHERS) # Setting the default here, as we may have no ssl module on import cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs if options is None: options = 0 # SSLv2 is easily broken and is considered harmful and dangerous options |= OP_NO_SSLv2 # SSLv3 has several problems and is now dangerous options |= OP_NO_SSLv3 # Disable compression to prevent CRIME attacks for OpenSSL 1.0+ # (issue #309) options |= OP_NO_COMPRESSION # TLSv1.2 only. Unless set explicitly, do not request tickets. # This may save some bandwidth on wire, and although the ticket is encrypted, # there is a risk associated with it being on wire, # if the server is not rotating its ticketing keys properly. options |= OP_NO_TICKET context.options |= options # Enable post-handshake authentication for TLS 1.3, see GH #1634. PHA is # necessary for conditional client cert authentication with TLS 1.3. # The attribute is None for OpenSSL <= 1.1.0 or does not exist in older # versions of Python. We only enable on Python 3.7.4+ or if certificate # verification is enabled to work around Python issue #37428 # See: https://bugs.python.org/issue37428 if (cert_reqs == ssl.CERT_REQUIRED or sys.version_info >= (3, 7, 4)) and getattr(context, "post_handshake_auth", None) is not None: context.post_handshake_auth = True context.verify_mode = cert_reqs # We ask for verification here but it may be disabled in HTTPSConnection.connect context.check_hostname = cert_reqs == ssl.CERT_REQUIRED if hasattr(context, "hostname_checks_common_name"): context.hostname_checks_common_name = False # Enable logging of TLS session keys via defacto standard environment variable # 'SSLKEYLOGFILE', if the feature is available (Python 3.8+). Skip empty values. if hasattr(context, "keylog_filename"): sslkeylogfile = os.environ.get("SSLKEYLOGFILE") if sslkeylogfile: context.keylog_filename = sslkeylogfile return context
def ssl_context() -> SSLContext: context = SSLContext() context.load_default_certs() context.check_hostname = False context.verify_mode = CERT_NONE return context
def open_url(url, data=None, headers=None, method=None, use_proxy=True, force=False, last_mod_time=None, timeout=10, validate_certs=True, url_username=None, url_password=None, http_agent=None, force_basic_auth=False): ''' Fetches a file from an HTTP/FTP server using urllib2 ''' handlers = [] # FIXME: change the following to use the generic_urlparse function # to remove the indexed references for 'parsed' parsed = urlparse.urlparse(url) if parsed[0] == 'https' and validate_certs: if not HAS_SSL: raise NoSSLError( 'SSL validation is not available in your version of python. You can use validate_certs=False, however this is unsafe and not recommended' ) # do the cert validation netloc = parsed[1] if '@' in netloc: netloc = netloc.split('@', 1)[1] if ':' in netloc: hostname, port = netloc.split(':', 1) port = int(port) else: hostname = netloc port = 443 # create the SSL validation handler and # add it to the list of handlers ssl_handler = SSLValidationHandler(hostname, port) handlers.append(ssl_handler) if parsed[0] != 'ftp': username = url_username if username: password = url_password netloc = parsed[1] elif '@' in parsed[1]: credentials, netloc = parsed[1].split('@', 1) if ':' in credentials: username, password = credentials.split(':', 1) else: username = credentials password = '' parsed = list(parsed) parsed[1] = netloc # reconstruct url without credentials url = urlparse.urlunparse(parsed) if username and not force_basic_auth: passman = urllib2.HTTPPasswordMgrWithDefaultRealm() # this creates a password manager passman.add_password(None, netloc, username, password) # because we have put None at the start it will always # use this username/password combination for urls # for which `theurl` is a super-url authhandler = urllib2.HTTPBasicAuthHandler(passman) # create the AuthHandler handlers.append(authhandler) elif username and force_basic_auth: if headers is None: headers = {} headers["Authorization"] = "Basic %s" % base64.b64encode( "%s:%s" % (username, password)) if not use_proxy: proxyhandler = urllib2.ProxyHandler({}) handlers.append(proxyhandler) # pre-2.6 versions of python cannot use the custom https # handler, since the socket class is lacking create_connection. # Some python builds lack HTTPS support. if hasattr(socket, 'create_connection') and CustomHTTPSHandler: handlers.append(CustomHTTPSHandler) opener = urllib2.build_opener(*handlers) urllib2.install_opener(opener) if method: if method.upper() not in ('OPTIONS', 'GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'TRACE', 'CONNECT', 'PATCH'): raise ConnectionError('invalid HTTP request method; %s' % method.upper()) request = RequestWithMethod(url, method.upper(), data) else: request = urllib2.Request(url, data) # add the custom agent header, to help prevent issues # with sites that block the default urllib agent string request.add_header('User-agent', http_agent) # if we're ok with getting a 304, set the timestamp in the # header, otherwise make sure we don't get a cached copy if last_mod_time and not force: tstamp = last_mod_time.strftime('%a, %d %b %Y %H:%M:%S +0000') request.add_header('If-Modified-Since', tstamp) else: request.add_header('cache-control', 'no-cache') # user defined headers now, which may override things we've set above if headers: if not isinstance(headers, dict): raise ValueError("headers provided to fetch_url() must be a dict") for header in headers: request.add_header(header, headers[header]) urlopen_args = [request, None] if sys.version_info >= (2, 6, 0): # urlopen in python prior to 2.6.0 did not # have a timeout parameter urlopen_args.append(timeout) if HAS_SSLCONTEXT and not validate_certs: # In 2.7.9, the default context validates certificates context = SSLContext(ssl.PROTOCOL_SSLv23) context.options |= ssl.OP_NO_SSLv2 context.options |= ssl.OP_NO_SSLv3 context.verify_mode = ssl.CERT_NONE context.check_hostname = False urlopen_args += (None, None, None, context) r = urllib2.urlopen(*urlopen_args) return r
# versions of Python. We only enable on Python 3.7.4+ or if certificate # verification is enabled to work around Python issue #37428 # See: https://bugs.python.org/issue37428 if (cert_reqs == ssl.CERT_REQUIRED or sys.version_info >= (3, 7, 4)) and getattr( context, "post_handshake_auth", None ) is not None: context.post_handshake_auth = True context.verify_mode = cert_reqs if ( getattr(context, "check_hostname", None) is not None ): # Platform-specific: Python 3.2 >>>>>>> master # We do our own verification, including fingerprints and alternative # hostnames. So disable it here context.check_hostname = False return context <<<<<<< HEAD def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None, ca_certs=None, server_hostname=None, ssl_version=None, ciphers=None, ssl_context=None, ca_cert_dir=None, key_password=None): ======= def ssl_wrap_socket( sock, keyfile=None, certfile=None, cert_reqs=None, ca_certs=None,
def handle_connection(self): """ Run connection handling routine. """ context = SSLContext(PROTOCOL_TLS_CLIENT) context.check_hostname = False context.verify_mode = CERT_NONE with create_connection( (self.server_host, self.server_port)) as self.socket: with context.wrap_socket( self.socket, server_hostname=self.server_host) as self.tls: # Use this buffer for all reads read_buffer = bytearray(4096) # Perform SID handshake rq = RQ_Cvid() rq.uuid = os.environ["S7S_UUID"] rq.instance = InstanceType.CLIENT rq.instance_flavor = InstanceFlavor.CLIENT_BRIGHTSTONE msg = MSG() setattr(msg, "payload", rq.SerializeToString()) setattr(msg, "id", randint(0, 65535)) self.tls.write(_VarintBytes(msg.ByteSize())) self.tls.sendall(msg.SerializeToString()) read = self.tls.recv_into(read_buffer, 4096) if read == 0: raise EOFError("") msg_len, msg_start = _DecodeVarint32(read_buffer, 0) msg = MSG() msg.ParseFromString(read_buffer[msg_start:msg_start + msg_len]) rs = RS_Cvid() rs.ParseFromString(msg.payload) self.server_cvid = rs.server_cvid self.sid = rs.sid # The connection is now connected with self.connection_state_cv: self.connection_state = ConnectionState.CONNECTED self.connection_state_cv.notify() # Begin accepting messages while True: # TODO there may be another message in the read buffer # Read from the socket read = self.tls.recv_into(read_buffer, 4096) if read == 0: raise EOFError("") n = 0 while n < read: msg_len, n = _DecodeVarint32(read_buffer, n) msg = MSG() msg.ParseFromString(read_buffer[n:n + msg_len]) # Place message in response map with self.response_map_cv: self.response_map[msg.id] = msg self.response_map_cv.notify() # The connection is now closed with self.connection_state_cv: self.connection_state = ConnectionState.CLOSED self.connection_state_cv.notify()
def setup_ssl_context(cert, private, hostname=False): ssl_context = SSLContext(PROTOCOL_SSLv23) ssl_context.load_cert_chain(cert, private) ssl_context.check_hostname = hostname return ssl_context
def get_ssl_context(*args): """Create and return an SSLContext object.""" certfile, keyfile, passphrase, ca_certs, cert_reqs, crlfile = args # Note PROTOCOL_SSLv23 is about the most misleading name imaginable. # This configures the server and client to negotiate the # highest protocol version they both support. A very good thing. # PROTOCOL_TLS_CLIENT was added in CPython 3.6, deprecating # PROTOCOL_SSLv23. ctx = SSLContext( getattr(ssl, "PROTOCOL_TLS_CLIENT", ssl.PROTOCOL_SSLv23)) # SSLContext.check_hostname was added in CPython 2.7.9 and 3.4. # PROTOCOL_TLS_CLIENT enables it by default. Using it # requires passing server_hostname to wrap_socket, which we already # do for SNI support. To support older versions of Python we have to # call match_hostname directly, so we disable check_hostname explicitly # to avoid calling match_hostname twice. if hasattr(ctx, "check_hostname"): ctx.check_hostname = False if hasattr(ctx, "options"): # Explicitly disable SSLv2, SSLv3 and TLS compression. Note that # up to date versions of MongoDB 2.4 and above already disable # SSLv2 and SSLv3, python disables SSLv2 by default in >= 2.7.7 # and >= 3.3.4 and SSLv3 in >= 3.4.3. There is no way for us to do # any of this explicitly for python 2.6 or 2.7 before 2.7.9. ctx.options |= getattr(ssl, "OP_NO_SSLv2", 0) ctx.options |= getattr(ssl, "OP_NO_SSLv3", 0) # OpenSSL >= 1.0.0 ctx.options |= getattr(ssl, "OP_NO_COMPRESSION", 0) if certfile is not None: try: if passphrase is not None: vi = sys.version_info # Since python just added a new parameter to an existing method # this seems to be about the best we can do. if (vi[0] == 2 and vi < (2, 7, 9) or vi[0] == 3 and vi < (3, 3)): raise ConfigurationError( "Support for ssl_pem_passphrase requires " "python 2.7.9+ (pypy 2.5.1+) or 3.3+") ctx.load_cert_chain(certfile, keyfile, passphrase) else: ctx.load_cert_chain(certfile, keyfile) except ssl.SSLError as exc: raise ConfigurationError( "Private key doesn't match certificate: %s" % (exc,)) if crlfile is not None: if not hasattr(ctx, "verify_flags"): raise ConfigurationError( "Support for ssl_crlfile requires " "python 2.7.9+ (pypy 2.5.1+) or 3.4+") # Match the server's behavior. ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF ctx.load_verify_locations(crlfile) if ca_certs is not None: ctx.load_verify_locations(ca_certs) elif cert_reqs != ssl.CERT_NONE: # CPython >= 2.7.9 or >= 3.4.0, pypy >= 2.5.1 if hasattr(ctx, "load_default_certs"): ctx.load_default_certs() # Python >= 3.2.0, useless on Windows. elif (sys.platform != "win32" and hasattr(ctx, "set_default_verify_paths")): ctx.set_default_verify_paths() elif sys.platform == "win32" and HAVE_WINCERTSTORE: with _WINCERTSLOCK: if _WINCERTS is None: _load_wincerts() ctx.load_verify_locations(_WINCERTS.name) elif HAVE_CERTIFI: ctx.load_verify_locations(certifi.where()) else: raise ConfigurationError( "`ssl_cert_reqs` is not ssl.CERT_NONE and no system " "CA certificates could be loaded. `ssl_ca_certs` is " "required.") ctx.verify_mode = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs return ctx
def create_urllib3_context( ssl_version: Optional[int] = None, cert_reqs: Optional[int] = None, options: Optional[int] = None, ciphers: Optional[str] = None, ssl_minimum_version: Optional[int] = None, ssl_maximum_version: Optional[int] = None, ) -> "ssl.SSLContext": """All arguments have the same meaning as ``ssl_wrap_socket``. By default, this function does a lot of the same work that ``ssl.create_default_context`` does on Python 3.4+. It: - Disables SSLv2, SSLv3, and compression - Sets a restricted set of server ciphers If you wish to enable SSLv3, you can do:: from urllib3.util import ssl_ context = ssl_.create_urllib3_context() context.options &= ~ssl_.OP_NO_SSLv3 You can do the same to enable compression (substituting ``COMPRESSION`` for ``SSLv3`` in the last line above). :param ssl_version: The desired protocol version to use. This will default to PROTOCOL_SSLv23 which will negotiate the highest protocol that both the server and your installation of OpenSSL support. This parameter is deprecated instead use 'ssl_minimum_version'. :param ssl_minimum_version: The minimum version of TLS to be used. Use the 'ssl.TLSVersion' enum for specifying the value. :param ssl_maximum_version: The maximum version of TLS to be used. Use the 'ssl.TLSVersion' enum for specifying the value. Not recommended to set to anything other than 'ssl.TLSVersion.MAXIMUM_SUPPORTED' which is the default value. :param cert_reqs: Whether to require the certificate verification. This defaults to ``ssl.CERT_REQUIRED``. :param options: Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``, ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``, and ``ssl.OP_NO_TICKET``. :param ciphers: Which cipher suites to allow the server to select. Defaults to either system configured ciphers if OpenSSL 1.1.1+, otherwise uses a secure default set of ciphers. :returns: Constructed SSLContext object with specified options :rtype: SSLContext """ if SSLContext is None: raise TypeError( "Can't create an SSLContext object without an ssl module") # This means 'ssl_version' was specified as an exact value. if ssl_version not in (None, PROTOCOL_TLS, PROTOCOL_TLS_CLIENT): # Disallow setting 'ssl_version' and 'ssl_minimum|maximum_version' # to avoid conflicts. if ssl_minimum_version is not None or ssl_maximum_version is not None: raise ValueError("Can't specify both 'ssl_version' and either " "'ssl_minimum_version' or 'ssl_maximum_version'") # 'ssl_version' is deprecated and will be removed in the future. else: # Use 'ssl_minimum_version' and 'ssl_maximum_version' instead. ssl_minimum_version = _SSL_VERSION_TO_TLS_VERSION.get( ssl_version, TLSVersion.MINIMUM_SUPPORTED) ssl_maximum_version = _SSL_VERSION_TO_TLS_VERSION.get( ssl_version, TLSVersion.MAXIMUM_SUPPORTED) # This warning message is pushing users to use 'ssl_minimum_version' # instead of both min/max. Best practice is to only set the minimum version and # keep the maximum version to be it's default value: 'TLSVersion.MAXIMUM_SUPPORTED' warnings.warn( "'ssl_version' option is deprecated and will be " "removed in a future release of urllib3 2.x. Instead " "use 'ssl_minimum_version'", category=DeprecationWarning, stacklevel=2, ) # PROTOCOL_TLS is deprecated in Python 3.10 so we always use PROTOCOL_TLS_CLIENT context = SSLContext(PROTOCOL_TLS_CLIENT) if ssl_minimum_version is not None: context.minimum_version = ssl_minimum_version else: # Python <3.10 defaults to 'MINIMUM_SUPPORTED' so explicitly set TLSv1.2 here context.minimum_version = TLSVersion.TLSv1_2 if ssl_maximum_version is not None: context.maximum_version = ssl_maximum_version # Unless we're given ciphers defer to either system ciphers in # the case of OpenSSL 1.1.1+ or use our own secure default ciphers. if ciphers is not None or not USE_DEFAULT_SSLCONTEXT_CIPHERS: context.set_ciphers(ciphers or DEFAULT_CIPHERS) # Setting the default here, as we may have no ssl module on import cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs if options is None: options = 0 # SSLv2 is easily broken and is considered harmful and dangerous options |= OP_NO_SSLv2 # SSLv3 has several problems and is now dangerous options |= OP_NO_SSLv3 # Disable compression to prevent CRIME attacks for OpenSSL 1.0+ # (issue #309) options |= OP_NO_COMPRESSION # TLSv1.2 only. Unless set explicitly, do not request tickets. # This may save some bandwidth on wire, and although the ticket is encrypted, # there is a risk associated with it being on wire, # if the server is not rotating its ticketing keys properly. options |= OP_NO_TICKET context.options |= options # Enable post-handshake authentication for TLS 1.3, see GH #1634. PHA is # necessary for conditional client cert authentication with TLS 1.3. # The attribute is None for OpenSSL <= 1.1.0 or does not exist in older # versions of Python. We only enable on Python 3.7.4+ or if certificate # verification is enabled to work around Python issue #37428 # See: https://bugs.python.org/issue37428 if (cert_reqs == ssl.CERT_REQUIRED or sys.version_info >= (3, 7, 4)) and getattr(context, "post_handshake_auth", None) is not None: context.post_handshake_auth = True # The order of the below lines setting verify_mode and check_hostname # matter due to safe-guards SSLContext has to prevent an SSLContext with # check_hostname=True, verify_mode=NONE/OPTIONAL. # We always set 'check_hostname=False' for pyOpenSSL so we rely on our own # 'ssl.match_hostname()' implementation. if cert_reqs == ssl.CERT_REQUIRED and not IS_PYOPENSSL: context.verify_mode = cert_reqs context.check_hostname = True else: context.check_hostname = False context.verify_mode = cert_reqs try: context.hostname_checks_common_name = False except AttributeError: pass # Enable logging of TLS session keys via defacto standard environment variable # 'SSLKEYLOGFILE', if the feature is available (Python 3.8+). Skip empty values. if hasattr(context, "keylog_filename"): sslkeylogfile = os.environ.get("SSLKEYLOGFILE") if sslkeylogfile: context.keylog_filename = sslkeylogfile return context
def get_ssl_context(*args): """Create and return an SSLContext object.""" (certfile, keyfile, passphrase, ca_certs, cert_reqs, crlfile, match_hostname) = args verify_mode = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs # Note PROTOCOL_SSLv23 is about the most misleading name imaginable. # This configures the server and client to negotiate the # highest protocol version they both support. A very good thing. # PROTOCOL_TLS_CLIENT was added in CPython 3.6, deprecating # PROTOCOL_SSLv23. ctx = SSLContext( getattr(ssl, "PROTOCOL_TLS_CLIENT", ssl.PROTOCOL_SSLv23)) # SSLContext.check_hostname was added in CPython 2.7.9 and 3.4. # PROTOCOL_TLS_CLIENT (added in Python 3.6) enables it by default. if hasattr(ctx, "check_hostname"): if _PY37PLUS and verify_mode != ssl.CERT_NONE: # Python 3.7 uses OpenSSL's hostname matching implementation # making it the obvious version to start using this with. # Python 3.6 might have been a good version, but it suffers # from https://bugs.python.org/issue32185. # We'll use our bundled match_hostname for older Python # versions, which also supports IP address matching # with Python < 3.5. ctx.check_hostname = match_hostname else: ctx.check_hostname = False if hasattr(ctx, "options"): # Explicitly disable SSLv2, SSLv3 and TLS compression. Note that # up to date versions of MongoDB 2.4 and above already disable # SSLv2 and SSLv3, python disables SSLv2 by default in >= 2.7.7 # and >= 3.3.4 and SSLv3 in >= 3.4.3. There is no way for us to do # any of this explicitly for python 2.6 or 2.7 before 2.7.9. ctx.options |= getattr(ssl, "OP_NO_SSLv2", 0) ctx.options |= getattr(ssl, "OP_NO_SSLv3", 0) # OpenSSL >= 1.0.0 ctx.options |= getattr(ssl, "OP_NO_COMPRESSION", 0) if certfile is not None: try: if passphrase is not None: vi = sys.version_info # Since python just added a new parameter to an existing method # this seems to be about the best we can do. if (vi[0] == 2 and vi < (2, 7, 9) or vi[0] == 3 and vi < (3, 3)): raise ConfigurationError( "Support for ssl_pem_passphrase requires " "python 2.7.9+ (pypy 2.5.1+) or 3.3+") ctx.load_cert_chain(certfile, keyfile, passphrase) else: ctx.load_cert_chain(certfile, keyfile) except ssl.SSLError as exc: raise ConfigurationError( "Private key doesn't match certificate: %s" % (exc, )) if crlfile is not None: if not hasattr(ctx, "verify_flags"): raise ConfigurationError( "Support for ssl_crlfile requires " "python 2.7.9+ (pypy 2.5.1+) or 3.4+") # Match the server's behavior. ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF ctx.load_verify_locations(crlfile) if ca_certs is not None: ctx.load_verify_locations(ca_certs) elif cert_reqs != ssl.CERT_NONE: # CPython >= 2.7.9 or >= 3.4.0, pypy >= 2.5.1 if hasattr(ctx, "load_default_certs"): ctx.load_default_certs() # Python >= 3.2.0, useless on Windows. elif (sys.platform != "win32" and hasattr(ctx, "set_default_verify_paths")): ctx.set_default_verify_paths() elif sys.platform == "win32" and HAVE_WINCERTSTORE: with _WINCERTSLOCK: if _WINCERTS is None: _load_wincerts() ctx.load_verify_locations(_WINCERTS.name) elif HAVE_CERTIFI: ctx.load_verify_locations(certifi.where()) else: raise ConfigurationError( "`ssl_cert_reqs` is not ssl.CERT_NONE and no system " "CA certificates could be loaded. `ssl_ca_certs` is " "required.") ctx.verify_mode = verify_mode return ctx
def create_urllib3_context( ssl_version=None, cert_reqs=None, options=None, ciphers=None ): """All arguments have the same meaning as ``ssl_wrap_socket``. By default, this function does a lot of the same work that ``ssl.create_default_context`` does on Python 3.4+. It: - Disables SSLv2, SSLv3, and compression - Sets a restricted set of server ciphers If you wish to enable SSLv3, you can do:: from urllib3.util import ssl_ context = ssl_.create_urllib3_context() context.options &= ~ssl_.OP_NO_SSLv3 You can do the same to enable compression (substituting ``COMPRESSION`` for ``SSLv3`` in the last line above). :param ssl_version: The desired protocol version to use. This will default to PROTOCOL_SSLv23 which will negotiate the highest protocol that both the server and your installation of OpenSSL support. :param cert_reqs: Whether to require the certificate verification. This defaults to ``ssl.CERT_REQUIRED``. :param options: Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``, ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``. :param ciphers: Which cipher suites to allow the server to select. :returns: Constructed SSLContext object with specified options :rtype: SSLContext """ context = SSLContext(ssl_version or PROTOCOL_TLS) context.set_ciphers(ciphers or DEFAULT_CIPHERS) # Setting the default here, as we may have no ssl module on import cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs if options is None: options = 0 # SSLv2 is easily broken and is considered harmful and dangerous options |= OP_NO_SSLv2 # SSLv3 has several problems and is now dangerous options |= OP_NO_SSLv3 # Disable compression to prevent CRIME attacks for OpenSSL 1.0+ # (issue #309) options |= OP_NO_COMPRESSION context.options |= options # Enable post-handshake authentication for TLS 1.3, see GH #1634. PHA is # necessary for conditional client cert authentication with TLS 1.3. # The attribute is None for OpenSSL <= 1.1.0 or does not exist in older # versions of Python. We only enable on Python 3.7.4+ or if certificate # verification is enabled to work around Python issue #37428 # See: https://bugs.python.org/issue37428 if (cert_reqs == ssl.CERT_REQUIRED or sys.version_info >= (3, 7, 4)) and getattr( context, "post_handshake_auth", None ) is not None: context.post_handshake_auth = True context.verify_mode = cert_reqs if ( getattr(context, "check_hostname", None) is not None ): # Platform-specific: Python 3.2 # We do our own verification, including fingerprints and alternative # hostnames. So disable it here context.check_hostname = False # Enable logging of TLS session keys via defacto standard environment variable # 'SSLKEYLOGFILE', if the feature is available (Python 3.8+). if hasattr(context, "keylog_filename"): context.keylog_filename = os.environ.get("SSLKEYLOGFILE") return context
def main(): # initialize variables used through the main function exitcode = 1 use_proxy = True proxy_protocol = '' proxy_url = '' base_url = '' ini_file = '' extract_path = '' # read configuration file name if supplied as command line argument if len(argv) > 1: cfg_file_name = str(argv[1]) else: cfg_file_name = 'uvlinux_updater.cfg' # try to parse configuration, otherwise use default settings try: config = ConfigParser(interpolation=None) config.read(cfg_file_name) use_proxy = config.getboolean('Config', 'use_proxy') if use_proxy: proxy_protocol = config.get('Config', 'proxy_protocol') proxy_url = config.get('Config', 'proxy_url') base_url = config.get('Config', 'base_url') ini_file = config.get('Config', 'ini_file') extract_path = config.get('Config', 'extract_path') print('Successfully read settings from configfile ' + cfg_file_name) except Exception as e: print(e) print('Failed to read settings from configfile ' + cfg_file_name + '. Using default settings.') use_proxy = True proxy_protocol = 'https' proxy_url = 'http://10.0.14.121:3128' base_url = 'https://update.nai.com/products/commonupdater' ini_file = 'avvdat.ini' extract_path = '/usr/local/uvscan/' pass # set up handler for our http(s) proxy proxy_handler = ur.ProxyHandler() if use_proxy: proxy_handler = ur.ProxyHandler({proxy_protocol: proxy_url}) # set up handler to allow only secure protocols, but do not verify hostname against certificate, as it does not match ('update.nai.com' vs. 'a248.e.akamai.net') ssl_context = SSLContext(PROTOCOL_SSLv23) ssl_context.options |= OP_NO_TLSv1 ssl_context.options |= OP_NO_SSLv3 ssl_context.options |= OP_NO_SSLv2 ssl_context.options |= OP_NO_COMPRESSION ssl_context.check_hostname = False # pull filename of most current archive (e.g. avvdat-8737.dat) & md5 hash from ini file on McAfee Server filename, hash_md5, filepath, filesize = getcurrent_filename_and_hash( proxy_handler, ssl_context, base_url + '/' + ini_file) # clean up returned values/types if needed (Python 2 Backport of Python 3 configparser module quirk) if type(filename) is list: filename = str(filename[0]) if type(hash_md5) is list: hash_md5 = str(hash_md5[0]) # check whether getcurrent_filename_and_hash() was successful if filename == '': print("Error, could not get current filename") else: # download current archive (e.g. avvdat-8737.dat) from McAfee Server tmp_file = download_archive(base_url + filepath, filename, proxy_handler, ssl_context, filesize) # prepare path archive will be extracted to #dest_dir = path.join(extract_path) # only extract if downloaded and actual md5 matches if md5match(tmp_file, hash_md5): print('MD5 hash matches, extracting ' + str(tmp_file) + ' to ' + extract_path) try: unzip(tmp_file, extract_path) except Exception as e: print(e) pass else: print('Extracted successfully into ' + extract_path) exitcode = 0 else: print('MD5 hash does not match!') # remove downloaded archive in either case print('Removing downloaded archive ' + str(tmp_file)) try: remove(tmp_file) except Exception as e: print(e) return (exitcode)