From 89735a5fd3c81e8aba3cb7b1d4836c1bf1e8c098 Mon Sep 17 00:00:00 2001 From: kali Date: Tue, 18 Sep 2012 22:55:45 +0900 Subject: cert verification and malformed json checks --- src/leap/eip/checks.py | 65 ++++++++++++++++++++++++++++++------------- src/leap/eip/eipconnection.py | 26 +++++++++++++++-- src/leap/eip/exceptions.py | 15 +++++++++- 3 files changed, 83 insertions(+), 23 deletions(-) (limited to 'src/leap/eip') diff --git a/src/leap/eip/checks.py b/src/leap/eip/checks.py index aea5a5d7..b55f5827 100644 --- a/src/leap/eip/checks.py +++ b/src/leap/eip/checks.py @@ -9,6 +9,8 @@ import netifaces import ping import requests +from leap import __branding as BRANDING +from leap import certs from leap.base import constants as baseconstants from leap.base import providers from leap.eip import config as eipconfig @@ -20,6 +22,11 @@ from leap.util.fileutil import mkdir_p logger = logging.getLogger(name=__name__) """ +ProviderCertChecker +------------------- +Checks on certificates. To be moved to base. +docs TBD + EIPConfigChecker ---------- It is used from the eip conductor (a instance of EIPConnection that is @@ -36,14 +43,15 @@ LeapNetworkChecker ------------------ Network checks. To be moved to base. docs TBD - -ProviderCertChecker -------------------- -Checks on certificates. -docs TBD """ +def get_ca_cert(): + ca_file = BRANDING.get('provider_ca_file') + if ca_file: + return certs.where(ca_file) + + class LeapNetworkChecker(object): """ all network related checks @@ -67,6 +75,7 @@ class LeapNetworkChecker(object): # XXX we probably should raise an exception here? # unless we use this as smoke test try: + # XXX remove this hardcoded random ip requests.get('http://216.172.161.165') except (requests.HTTPError, requests.RequestException) as e: self.error = e.message @@ -124,7 +133,7 @@ class ProviderCertChecker(object): """ def __init__(self, fetcher=requests): self.fetcher = fetcher - self.cacert = None + self.cacert = get_ca_cert() def run_all(self, checker=None, skip_download=False): if not checker: @@ -159,25 +168,34 @@ class ProviderCertChecker(object): raise NotImplementedError def is_there_provider_ca(self): - # XXX fake it till you make it! :P + from leap import certs + logger.debug('do we have provider_ca?') + cacert_path = BRANDING.get('provider_ca_file', None) + if not cacert_path: + logger.debug('False') + return False + self.cacert = certs.where(cacert_path) + logger.debug('True') return True - # enable this when we have - # a custom "branded" bundle - # certs package. - try: - from leap.custom import certs - except ImportError: - raise - self.cacert = certs.where('cacert.pem') - def is_https_working(self, uri=None, verify=True): + if uri is None: + uri = self._get_root_uri() # XXX raise InsecureURI or something better + logger.debug('is https working?') + logger.debug('uri: %s', uri) + #import ipdb;ipdb.set_trace() assert uri.startswith('https') if verify is True and self.cacert is not None: + logger.debug('verify cert: %s', self.cacert) verify = self.cacert - self.fetcher.get(uri, verify=verify) - return True + try: + self.fetcher.get(uri, verify=verify) + except requests.exceptions.SSLError: + raise eipexceptions.EIPBadCertError + else: + logger.debug('True') + return True def check_new_cert_needed(self, skip_download=False): if not self.is_cert_valid(do_raise=False): @@ -256,7 +274,11 @@ class ProviderCertChecker(object): raise return True + def _get_root_uri(self): + return u"https://%s/" % baseconstants.DEFAULT_PROVIDER + def _get_client_cert_uri(self): + # XXX get the whole thing from constants return "https://%s/cert/get" % (baseconstants.DEFAULT_PROVIDER) def _get_client_cert_path(self): @@ -370,7 +392,12 @@ class EIPConfigChecker(object): domain = config.get('provider', None) uri = self._get_provider_definition_uri(domain=domain) - self.defaultprovider.load(from_uri=uri, fetcher=self.fetcher) + # FIXME! Pass ca path verify!!! + self.defaultprovider.load( + from_uri=uri, + fetcher=self.fetcher, + verify=False) + #import ipdb;ipdb.set_trace() self.defaultprovider.save() def fetch_eip_service_config(self, skip_download=False, diff --git a/src/leap/eip/eipconnection.py b/src/leap/eip/eipconnection.py index d1c84b2a..4e240f16 100644 --- a/src/leap/eip/eipconnection.py +++ b/src/leap/eip/eipconnection.py @@ -6,6 +6,7 @@ import logging import Queue import sys +from leap.eip.checks import ProviderCertChecker from leap.eip.checks import EIPConfigChecker from leap.eip import config as eipconfig from leap.eip import exceptions as eip_exceptions @@ -22,7 +23,10 @@ class EIPConnection(OpenVPNConnection): Status updates (connected, bandwidth, etc) are signaled to the GUI. """ - def __init__(self, config_checker=EIPConfigChecker, *args, **kwargs): + def __init__(self, + provider_cert_checker=ProviderCertChecker, + config_checker=EIPConfigChecker, + *args, **kwargs): self.settingsfile = kwargs.get('settingsfile', None) self.logfile = kwargs.get('logfile', None) @@ -30,6 +34,8 @@ class EIPConnection(OpenVPNConnection): status_signals = kwargs.pop('status_signals', None) self.status = EIPConnectionStatus(callbacks=status_signals) + + self.provider_cert_checker = provider_cert_checker() self.config_checker = config_checker() host = eipconfig.get_socket_path() @@ -45,12 +51,25 @@ class EIPConnection(OpenVPNConnection): run all eip checks previous to attempting a connection """ logger.debug('running conductor checks') + + def push_err(exc): + # keep the original traceback! + exc_traceback = sys.exc_info()[2] + self.error_queue.put((exc, exc_traceback)) + + try: + # network (1) + self.provider_cert_checker.run_all() + except Exception as exc: + push_err(exc) try: self.config_checker.run_all(skip_download=skip_download) + except Exception as exc: + push_err(exc) + try: self.run_openvpn_checks() except Exception as exc: - exc_traceback = sys.exc_info()[2] - self.error_queue.put((exc, exc_traceback)) + push_err(exc) def connect(self): """ @@ -84,6 +103,7 @@ class EIPConnection(OpenVPNConnection): # XXX this separation does not # make sense anymore after having # merged Connection and Manager classes. + # XXX GET RID OF THIS FUNCTION HERE! try: state = self.get_connection_state() except eip_exceptions.ConnectionRefusedError: diff --git a/src/leap/eip/exceptions.py b/src/leap/eip/exceptions.py index 467be7fe..f048621f 100644 --- a/src/leap/eip/exceptions.py +++ b/src/leap/eip/exceptions.py @@ -40,6 +40,8 @@ class EIPClientError(Exception): base EIPClient exception """ critical = False + failfirst = False + warning = False class CriticalError(EIPClientError): @@ -54,7 +56,7 @@ class Warning(EIPClientError): """ just that, warnings """ - pass + warning = True class EIPNoPolkitAuthAgentAvailable(CriticalError): @@ -81,10 +83,21 @@ class EIPNoCommandError(EIPClientError): "
(Might be a permissions problem)") +class EIPBadCertError(Warning): + # XXX this should be critical and fail close + message = "cert verification failed" + usermessage = "there is a problem with provider certificate" + + +class LeapBadConfigFetchedError(Warning): + message = "provider sent a malformed json file" + usermessage = "an error occurred during configuratio of leap services" + # # errors still needing some love # + class EIPInitNoKeyFileError(CriticalError): message = "No vpn keys found in the expected path" usermessage = "We could not find your eip certs in the expected path" -- cgit v1.2.3