summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/leap/bitmask/bonafide/_protocol.py4
-rw-r--r--src/leap/bitmask/bonafide/config.py76
-rw-r--r--src/leap/bitmask/bonafide/session.py2
-rw-r--r--tests/integration/bonafide/cacert.pem30
-rw-r--r--tests/integration/bonafide/leaptest_combined_keycert.pem127
-rw-r--r--tests/integration/bonafide/leaptestscert.pem99
-rw-r--r--tests/integration/bonafide/test_config.py146
7 files changed, 449 insertions, 35 deletions
diff --git a/src/leap/bitmask/bonafide/_protocol.py b/src/leap/bitmask/bonafide/_protocol.py
index 0de5b7c..004359e 100644
--- a/src/leap/bitmask/bonafide/_protocol.py
+++ b/src/leap/bitmask/bonafide/_protocol.py
@@ -110,7 +110,7 @@ class BonafideProtocol(object):
provider = config.Provider(provider_id, autoconf=autoconf)
- def maybe_finish_provider_bootstrap(result, provider):
+ def maybe_finish_provider_bootstrap(result):
session = self._get_session(provider, full_id, password)
d = provider.download_services_config_with_auth(session)
d.addCallback(lambda _: result)
@@ -118,7 +118,7 @@ class BonafideProtocol(object):
d = provider.callWhenReady(
self._do_authenticate, provider, full_id, password)
- d.addCallback(maybe_finish_provider_bootstrap, provider)
+ d.addCallback(maybe_finish_provider_bootstrap)
return d
def _do_authenticate(self, provider, full_id, password):
diff --git a/src/leap/bitmask/bonafide/config.py b/src/leap/bitmask/bonafide/config.py
index 5f3bff9..1e6e550 100644
--- a/src/leap/bitmask/bonafide/config.py
+++ b/src/leap/bitmask/bonafide/config.py
@@ -32,17 +32,16 @@ from cryptography.x509 import load_pem_x509_certificate
from urlparse import urlparse
from twisted.internet import defer, reactor
-from twisted.internet.ssl import ClientContextFactory
from twisted.logger import Logger
-from twisted.web.client import Agent, downloadPage
+from twisted.web.client import downloadPage
-from leap.bitmask.bonafide._http import httpRequest
from leap.bitmask.bonafide.provider import Discovery
from leap.bitmask.bonafide.errors import NotConfiguredError, NetworkError
from leap.common.check import leap_assert
from leap.common.config import get_path_prefix as common_get_path_prefix
from leap.common.files import mkdir_p
+from leap.common.http import HTTPClient
APPNAME = "bonafide"
@@ -161,8 +160,6 @@ def delete_provider(domain):
class Provider(object):
- # TODO add validation
-
SERVICES_MAP = {
'openvpn': ['eip'],
'mx': ['soledad', 'smtp']}
@@ -174,8 +171,7 @@ class Provider(object):
stuck_bootstrap = defaultdict(None)
def __init__(self, domain, autoconf=False, basedir=None,
- check_certificate=True):
- # TODO: I need a way to know if it was already configured
+ cert_path=None):
if not basedir:
basedir = os.path.join(_preffix, 'leap')
self._basedir = os.path.expanduser(basedir)
@@ -184,18 +180,13 @@ class Provider(object):
self._provider_config = None
is_configured = self.is_configured()
- if not is_configured:
- check_certificate = False
-
- if check_certificate:
- self.contextFactory = None
+ if is_configured:
+ self._http = HTTPClient(self._get_ca_cert_path())
else:
- # XXX we should do this only for the FIRST provider download.
- # For the rest, we should pass the ca cert to the agent.
- # That means that RIGHT AFTER DOWNLOADING provider_info,
- # we should instantiate a new Agent...
- self.contextFactory = WebClientContextFactory()
- self._agent = Agent(reactor, self.contextFactory)
+ # TODO: we distribute our own cert bundle but it's too outdated,
+ # let's use for now the one from the system
+ # see: leap.common.ca_bundle.where()
+ self._http = HTTPClient(cert_path)
self._load_provider_json()
@@ -260,6 +251,8 @@ class Provider(object):
ongoing = self.ongoing_bootstrap.get(domain)
if ongoing:
self.log.debug('Already bootstrapping this provider...')
+ self.ongoing_bootstrap[domain].addCallback(
+ self._reload_http_client)
return
self.first_bootstrap[self._domain] = defer.Deferred()
@@ -270,10 +263,14 @@ class Provider(object):
except defer.AlreadyCalledError:
pass
+ def first_bootstrap_error(failure):
+ self.first_bootstrap[domain].errback(failure)
+ return failure
+
d = self.maybe_download_provider_info()
d.addCallback(self.maybe_download_ca_cert)
d.addCallback(self.validate_ca_cert)
- d.addCallback(first_bootstrap_done)
+ d.addCallbacks(first_bootstrap_done, first_bootstrap_error)
d.addCallback(self.maybe_download_services_config)
self.ongoing_bootstrap[domain] = d
@@ -311,7 +308,8 @@ class Provider(object):
shutil.rmtree(folders)
raise NetworkError(failure.getErrorMessage())
- d = downloadPage(uri, provider_json, method=met)
+ d = self._http.request(uri, method=met)
+ d.addCallback(_write_to_file, provider_json)
d.addCallback(lambda _: self._load_provider_json())
d.addErrback(errback)
return d
@@ -326,20 +324,27 @@ class Provider(object):
"""
:rtype: deferred
"""
-
- def errback(self, failure):
- raise NetworkError(failure.getErrorMessage())
-
path = self._get_ca_cert_path()
if is_file(path):
return defer.succeed('ca_cert_path_already_exists')
+ def errback(failure):
+ raise NetworkError(failure.getErrorMessage())
+
uri = self._get_ca_cert_uri()
mkdir_p(os.path.split(path)[0])
+
+ # We don't validate the TLS cert for this connection,
+ # just check the fingerprint of the ca.cert
d = downloadPage(uri, path)
+ d.addCallback(self._reload_http_client)
d.addErrback(errback)
return d
+ def _reload_http_client(self, ret):
+ self._http = HTTPClient(self._get_ca_cert_path())
+ return ret
+
def validate_ca_cert(self, ignored):
expected = self._get_expected_ca_cert_fingerprint()
algo, expectedfp = expected.split(':')
@@ -377,6 +382,12 @@ class Provider(object):
# UNAUTHENTICATED if we try to get the services
# See: # https://leap.se/code/issues/7906
+ def check_error(content):
+ c = json.loads(content)
+ if 'error' in c:
+ raise Exception(c['error'])
+ return content
+
def further_bootstrap_needs_auth(ignored):
self.log.warn('Cannot download services config yet, need auth')
pending_deferred = defer.Deferred()
@@ -385,7 +396,9 @@ class Provider(object):
uri, met, path = self._get_configs_download_params()
- d = downloadPage(uri, path, method=met)
+ d = self._http.request(uri, method=met)
+ d.addCallback(check_error)
+ d.addCallback(_write_to_file, path)
d.addCallback(lambda _: self._load_provider_json())
d.addCallback(
lambda _: self._get_config_for_all_services(session=None))
@@ -553,13 +566,10 @@ class Provider(object):
def _fetch_provider_configs_unauthenticated(self, uri, path):
self.log.info('Downloading config for %s...' % uri)
- d = downloadPage(uri, path, method='GET')
+ d = self._http.request(uri)
+ d.addCallback(_write_to_file, path)
return d
- def _http_request(self, *args, **kw):
- # XXX pass if-modified-since header
- return httpRequest(self._agent, *args, **kw)
-
class Record(object):
def __init__(self, **kw):
@@ -569,9 +579,9 @@ class Record(object):
return self.__dict__
-class WebClientContextFactory(ClientContextFactory):
- def getContext(self, hostname, port):
- return ClientContextFactory.getContext(self)
+def _write_to_file(content, path):
+ with open(path, 'w') as f:
+ f.write(content)
if __name__ == '__main__':
diff --git a/src/leap/bitmask/bonafide/session.py b/src/leap/bitmask/bonafide/session.py
index 551bfa2..a05e209 100644
--- a/src/leap/bitmask/bonafide/session.py
+++ b/src/leap/bitmask/bonafide/session.py
@@ -169,6 +169,8 @@ class Session(object):
return self._request(self._agent, uri, method=met)
def _request(self, *args, **kw):
+ # TODO: we are not pinning the TLS cert of the API
+ # maybe we can use leap.common.http
kw['token'] = self._token
return httpRequest(*args, **kw)
diff --git a/tests/integration/bonafide/cacert.pem b/tests/integration/bonafide/cacert.pem
new file mode 100644
index 0000000..30c69c6
--- /dev/null
+++ b/tests/integration/bonafide/cacert.pem
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFGDCCBACgAwIBAgIJAIu/QWMeEGrsMA0GCSqGSIb3DQEBBQUAMIG4MQswCQYD
+VQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkN5YmVyc3BhY2UxJzAlBgNV
+BAoTHkxFQVAgRW5jcnlwdGlvbiBBY2Nlc3MgUHJvamVjdDETMBEGA1UECxMKY3li
+ZXJzcGFjZTEWMBQGA1UEAxMNdGVzdHMtbGVhcC5zZTETMBEGA1UEKRMKdGVzdHMt
+bGVhcDEcMBoGCSqGSIb3DQEJARYNdGVzdHNAbGVhcC5zZTAeFw0xMzA5MDMxNTA0
+MTFaFw0yMzA5MDExNTA0MTFaMIG4MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
+EzARBgNVBAcTCkN5YmVyc3BhY2UxJzAlBgNVBAoTHkxFQVAgRW5jcnlwdGlvbiBB
+Y2Nlc3MgUHJvamVjdDETMBEGA1UECxMKY3liZXJzcGFjZTEWMBQGA1UEAxMNdGVz
+dHMtbGVhcC5zZTETMBEGA1UEKRMKdGVzdHMtbGVhcDEcMBoGCSqGSIb3DQEJARYN
+dGVzdHNAbGVhcC5zZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ9R
+L/azQ7jIzmB6+VEKFSdDw27DMq/aN87grNHqNAQiiU7b3hJLff9CAgMZhP92hB7X
+Wwg/TN7IEMLUacP0EChRekI6VtpsNBlfb5g/8yq4kORWhniY99dnjbJaw2sGA3Oh
+azySIvrKPxE/V393dmOQq+RFO4S+ytcq+rUILVFQX4lnFUHTyGGtpgMnB3smxJ8K
+WPu9bZej0GXjeWgVb28HxoqMEJC+4lScRZT/p7VhWN0QmOW3SP4l65guvDStdTGY
+z3uOFbGRuSRN9nHwTxe5COhyOa1TrEp89noHOGt3DRba4ZN4QUF3vX+c5JKaF6Ie
+s7LajB3hSWe/8ifT9oMCAwEAAaOCASEwggEdMB0GA1UdDgQWBBQ2GXCWqVz+o4IP
+eZUxUitKQb2ByzCB7QYDVR0jBIHlMIHigBQ2GXCWqVz+o4IPeZUxUitKQb2By6GB
+vqSBuzCBuDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRMwEQYDVQQHEwpDeWJl
+cnNwYWNlMScwJQYDVQQKEx5MRUFQIEVuY3J5cHRpb24gQWNjZXNzIFByb2plY3Qx
+EzARBgNVBAsTCmN5YmVyc3BhY2UxFjAUBgNVBAMTDXRlc3RzLWxlYXAuc2UxEzAR
+BgNVBCkTCnRlc3RzLWxlYXAxHDAaBgkqhkiG9w0BCQEWDXRlc3RzQGxlYXAuc2WC
+CQCLv0FjHhBq7DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBVBey7
+ohxU/ir7g3In+uk3iyfZT+yhmjz1j6IWqbno+sc3CfCOiEgTRTphFTN2aP6pvigD
+yKUBYZ0NRA5mAl3xopeT819DPkLgkacm4wugYKqV+60yrekmbEWsu/T5/jLWHN6s
+QelIKdLklA9oivM1lCIqR+XV4A2MX3zwXdEmZp8QYiBAqLf49wgCLhSOrgXXUlb0
+EUMsyclHs9PN33YRd9qQiE0hwBwpcxxus/sonnMP2xDiDiCu6dnYC7BmzfYfgiS5
+7tfEGpKyuY+7J+etOzOKfkNA20ooVRvvpQ4rpcHulKwZE3yI0geW7YS2uL+p5ORO
+twHvLcMPlAXUkXhS
+-----END CERTIFICATE-----
diff --git a/tests/integration/bonafide/leaptest_combined_keycert.pem b/tests/integration/bonafide/leaptest_combined_keycert.pem
new file mode 100644
index 0000000..f1e0fb2
--- /dev/null
+++ b/tests/integration/bonafide/leaptest_combined_keycert.pem
@@ -0,0 +1,127 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDAT67c8y4ORa6o
+/gor3gAouJI6W6R7YlPzzh4uaba4YhqgAEZzcZ7S589CqON8Eo8G2tQvh+ZSaNmP
+idFDjFxfpb1sBMb9Nu720s0V8UMxzCDh7oyePZGdKP+F04+MkB0eHWSObBrzsjsj
+KVsD/5fUeLbd1SdK1C2cKzsoRQ+GVEyMJeiISFlV05fxdAZSybPcwH+3aiVX+7cM
+9ek8bufIeqrAfZVdvO/2Fuv6WfR2MEe32XO/9gj02XSGWd6sPXMn/lflKvNNKEWC
+UWdqTArGi0CqQ4D+Q73ruUIthCJr+7LWK+7QKG980a1RR7GZJvs3skhUDh3eua2u
+ICPiqQLlAgMBAAECggEBAKJr6j0UagaF1dFG1eJc2neKA36kXdQTpOIaaKU8haVO
+vjv6X4YrJT/tpsAfEhp9Ni1M7r7CIcXiZjVz6bkKOA5UVhqAImxEVClEuw/YN688
+P11yc3NGftBkiwNFPk0yflUr7/zV0yGVm5rD1+oVme9KkO/kkg4CDA+E9664PTdu
+S4NVvL6OgHUG2nucqIz0kzUBapo7okIkvggfldeDYF47rn/e0VikNpKkMzoCzWs+
+3ryzldfigwg18rE2nltQYk/Mi+H30iNTNEonLjs9YbiDPn8iy5SZ7xY4lAO1Urev
+skdY04hmkOzh9JEETHeTj1LUIw7tfRdS3X6B+19gkCECgYEA+41UOLBb0ZHsGjsA
+aZBtI4g8mvGTOFe/Az7Jm0404z6e8AIe4NeSJoJ6oV6WG2BmKvqTViYT2QnmauHA
+WB1xJ5fH3PK7/LjICI2QE247E294+g5p1KYysALc2fChfJNpdfETzWJAUSSBFqxb
+amCDZ4Gc8S/V44fEkJKPLuAvxL0CgYEAw7YyGsEX+lDGzumFQY4wz20+Cyvilnx0
+xoFGQ85RSprZttU64PID/u1HD9/Nv4lGcBDcTTtrmOEk9x51YzttrsPF9sn+Wj0y
+eahuR32Qc1652Y7fAKgN2vIZRFBcGpAsemcoqmYFRMImX60G0areKaclooimTbJA
+Si52P4IKnUkCgYAI+07ah1F/9hncBedJ3aJH9oFTdvSuulNTplZEeVJiGsZKA4le
+tdO+FEKUqG/rolGDj1bbaJik0zmq70yS2NpFc6HrPa+Aoohh5cwTJYhudTh4lTMq
+KJT+u9tu3KynagwF7gmq96scOpVxXc4VykRm2bXk1rRoX1yhXNpH7jFGcQKBgCn/
+v2DebzbYftGIa4BV80OQPfBHyqhgrO6sb1e9vtQzxuTlfW0ogpMCeG1/qbegzeze
+sWghiEWWi0g80RQqfK80dBcx4dObrmlNK91LpOQdP+TgNBr/9Xk22xU96YYJyoG6
+AZAPtLG8uF9v0jbMZECsDfeDO60Qw5snvViDn6OBAoGACAbbQCbuh0cduDVwn0uz
+8XDyRTKDhOsJ3p6UB1TjwvbLeoPI93Dv1gpEeoqELtCu+ZXr3+/i/IbwrxucrFNn
+L/s+4zR2mlEAxBdtCFsH/Qf7+iYpBFSo4YReXz3xR+EVTmswzodJCbtF74oQSr6o
+7d56Rd/5k2UkFeXnlGOLyAc=
+-----END PRIVATE KEY-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 4 (0x4)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=US, ST=CA, L=Cyberspace, O=LEAP Encryption Access Project, OU=cyberspace, CN=tests-leap.se/name=tests-leap/emailAddress=tests@leap.se
+ Validity
+ Not Before: Sep 3 17:52:16 2013 GMT
+ Not After : Sep 1 17:52:16 2023 GMT
+ Subject: C=US, ST=CA, L=Cyberspace, O=LEAP Encryption Access Project, OU=cyberspace, CN=localhost/name=tests-leap/emailAddress=tests@leap.se
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c0:4f:ae:dc:f3:2e:0e:45:ae:a8:fe:0a:2b:de:
+ 00:28:b8:92:3a:5b:a4:7b:62:53:f3:ce:1e:2e:69:
+ b6:b8:62:1a:a0:00:46:73:71:9e:d2:e7:cf:42:a8:
+ e3:7c:12:8f:06:da:d4:2f:87:e6:52:68:d9:8f:89:
+ d1:43:8c:5c:5f:a5:bd:6c:04:c6:fd:36:ee:f6:d2:
+ cd:15:f1:43:31:cc:20:e1:ee:8c:9e:3d:91:9d:28:
+ ff:85:d3:8f:8c:90:1d:1e:1d:64:8e:6c:1a:f3:b2:
+ 3b:23:29:5b:03:ff:97:d4:78:b6:dd:d5:27:4a:d4:
+ 2d:9c:2b:3b:28:45:0f:86:54:4c:8c:25:e8:88:48:
+ 59:55:d3:97:f1:74:06:52:c9:b3:dc:c0:7f:b7:6a:
+ 25:57:fb:b7:0c:f5:e9:3c:6e:e7:c8:7a:aa:c0:7d:
+ 95:5d:bc:ef:f6:16:eb:fa:59:f4:76:30:47:b7:d9:
+ 73:bf:f6:08:f4:d9:74:86:59:de:ac:3d:73:27:fe:
+ 57:e5:2a:f3:4d:28:45:82:51:67:6a:4c:0a:c6:8b:
+ 40:aa:43:80:fe:43:bd:eb:b9:42:2d:84:22:6b:fb:
+ b2:d6:2b:ee:d0:28:6f:7c:d1:ad:51:47:b1:99:26:
+ fb:37:b2:48:54:0e:1d:de:b9:ad:ae:20:23:e2:a9:
+ 02:e5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Cert Type:
+ SSL Server
+ Netscape Comment:
+ Easy-RSA Generated Server Certificate
+ X509v3 Subject Key Identifier:
+ 51:92:B6:A3:D7:D6:EC:8F:FC:16:C5:D4:0F:87:CC:EA:5C:7C:17:81
+ X509v3 Authority Key Identifier:
+ keyid:36:19:70:96:A9:5C:FE:A3:82:0F:79:95:31:52:2B:4A:41:BD:81:CB
+ DirName:/C=US/ST=CA/L=Cyberspace/O=LEAP Encryption Access Project/OU=cyberspace/CN=tests-leap.se/name=tests-leap/emailAddress=tests@leap.se
+ serial:8B:BF:41:63:1E:10:6A:EC
+
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication
+ X509v3 Key Usage:
+ Digital Signature, Key Encipherment
+ Signature Algorithm: sha1WithRSAEncryption
+ 88:d9:35:e0:d9:fa:fd:6b:57:e2:4d:f6:ef:91:6f:56:a6:2b:
+ 1a:1e:ec:8f:b0:18:e3:ec:ca:c9:1e:78:07:1d:0f:cf:fe:09:
+ 21:84:25:c4:27:ea:22:d7:48:53:73:ed:78:0f:42:5c:c7:f7:
+ 38:04:84:df:67:99:fd:75:6f:e8:dc:3b:91:ab:fa:c7:32:e5:
+ fd:3b:ce:de:7c:6a:df:39:46:1e:46:3a:4d:e1:e1:60:f3:bf:
+ aa:b2:0b:5d:ee:f2:0c:ee:82:7f:b5:02:75:04:47:d5:2b:c8:
+ e0:6d:6a:10:4a:ca:e0:c3:4f:ee:ff:15:71:37:f5:4d:95:38:
+ fe:a3:da:84:46:90:04:c2:61:86:a0:7f:e2:7d:62:46:6d:f6:
+ f8:90:51:88:c3:f2:8c:ca:b3:89:40:9f:6b:8b:33:65:e1:fd:
+ 0f:8b:d7:6a:93:dc:de:be:85:07:c7:d1:1d:b5:db:70:54:9f:
+ 95:d8:fb:11:f7:a7:e6:90:ba:9b:28:0e:3d:47:7a:63:6d:60:
+ 44:f6:96:aa:b6:a2:bc:0a:e5:25:c8:a2:74:91:54:95:bb:e2:
+ 09:01:56:73:6e:56:e8:6f:d6:a5:d8:18:96:c1:82:ef:2c:9e:
+ e2:4c:94:bc:00:71:5e:16:49:6b:e4:94:7a:d1:0c:2e:f4:19:
+ b2:2a:c2:b8
+-----BEGIN CERTIFICATE-----
+MIIFdDCCBFygAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBuDELMAkGA1UEBhMCVVMx
+CzAJBgNVBAgTAkNBMRMwEQYDVQQHEwpDeWJlcnNwYWNlMScwJQYDVQQKEx5MRUFQ
+IEVuY3J5cHRpb24gQWNjZXNzIFByb2plY3QxEzARBgNVBAsTCmN5YmVyc3BhY2Ux
+FjAUBgNVBAMTDXRlc3RzLWxlYXAuc2UxEzARBgNVBCkTCnRlc3RzLWxlYXAxHDAa
+BgkqhkiG9w0BCQEWDXRlc3RzQGxlYXAuc2UwHhcNMTMwOTAzMTc1MjE2WhcNMjMw
+OTAxMTc1MjE2WjCBtDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRMwEQYDVQQH
+EwpDeWJlcnNwYWNlMScwJQYDVQQKEx5MRUFQIEVuY3J5cHRpb24gQWNjZXNzIFBy
+b2plY3QxEzARBgNVBAsTCmN5YmVyc3BhY2UxEjAQBgNVBAMTCWxvY2FsaG9zdDET
+MBEGA1UEKRMKdGVzdHMtbGVhcDEcMBoGCSqGSIb3DQEJARYNdGVzdHNAbGVhcC5z
+ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMBPrtzzLg5Frqj+Cive
+ACi4kjpbpHtiU/POHi5ptrhiGqAARnNxntLnz0Ko43wSjwba1C+H5lJo2Y+J0UOM
+XF+lvWwExv027vbSzRXxQzHMIOHujJ49kZ0o/4XTj4yQHR4dZI5sGvOyOyMpWwP/
+l9R4tt3VJ0rULZwrOyhFD4ZUTIwl6IhIWVXTl/F0BlLJs9zAf7dqJVf7twz16Txu
+58h6qsB9lV287/YW6/pZ9HYwR7fZc7/2CPTZdIZZ3qw9cyf+V+Uq800oRYJRZ2pM
+CsaLQKpDgP5Dveu5Qi2EImv7stYr7tAob3zRrVFHsZkm+zeySFQOHd65ra4gI+Kp
+AuUCAwEAAaOCAYkwggGFMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZAMDQG
+CWCGSAGG+EIBDQQnFiVFYXN5LVJTQSBHZW5lcmF0ZWQgU2VydmVyIENlcnRpZmlj
+YXRlMB0GA1UdDgQWBBRRkraj19bsj/wWxdQPh8zqXHwXgTCB7QYDVR0jBIHlMIHi
+gBQ2GXCWqVz+o4IPeZUxUitKQb2By6GBvqSBuzCBuDELMAkGA1UEBhMCVVMxCzAJ
+BgNVBAgTAkNBMRMwEQYDVQQHEwpDeWJlcnNwYWNlMScwJQYDVQQKEx5MRUFQIEVu
+Y3J5cHRpb24gQWNjZXNzIFByb2plY3QxEzARBgNVBAsTCmN5YmVyc3BhY2UxFjAU
+BgNVBAMTDXRlc3RzLWxlYXAuc2UxEzARBgNVBCkTCnRlc3RzLWxlYXAxHDAaBgkq
+hkiG9w0BCQEWDXRlc3RzQGxlYXAuc2WCCQCLv0FjHhBq7DATBgNVHSUEDDAKBggr
+BgEFBQcDATALBgNVHQ8EBAMCBaAwDQYJKoZIhvcNAQEFBQADggEBAIjZNeDZ+v1r
+V+JN9u+Rb1amKxoe7I+wGOPsyskeeAcdD8/+CSGEJcQn6iLXSFNz7XgPQlzH9zgE
+hN9nmf11b+jcO5Gr+scy5f07zt58at85Rh5GOk3h4WDzv6qyC13u8gzugn+1AnUE
+R9UryOBtahBKyuDDT+7/FXE39U2VOP6j2oRGkATCYYagf+J9YkZt9viQUYjD8ozK
+s4lAn2uLM2Xh/Q+L12qT3N6+hQfH0R2123BUn5XY+xH3p+aQupsoDj1HemNtYET2
+lqq2orwK5SXIonSRVJW74gkBVnNuVuhv1qXYGJbBgu8snuJMlLwAcV4WSWvklHrR
+DC70GbIqwrg=
+-----END CERTIFICATE-----
diff --git a/tests/integration/bonafide/leaptestscert.pem b/tests/integration/bonafide/leaptestscert.pem
new file mode 100644
index 0000000..7cb9265
--- /dev/null
+++ b/tests/integration/bonafide/leaptestscert.pem
@@ -0,0 +1,99 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 4 (0x4)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=US, ST=CA, L=Cyberspace, O=LEAP Encryption Access Project, OU=cyberspace, CN=tests-leap.se/name=tests-leap/emailAddress=tests@leap.se
+ Validity
+ Not Before: Sep 3 17:52:16 2013 GMT
+ Not After : Sep 1 17:52:16 2023 GMT
+ Subject: C=US, ST=CA, L=Cyberspace, O=LEAP Encryption Access Project, OU=cyberspace, CN=localhost/name=tests-leap/emailAddress=tests@leap.se
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c0:4f:ae:dc:f3:2e:0e:45:ae:a8:fe:0a:2b:de:
+ 00:28:b8:92:3a:5b:a4:7b:62:53:f3:ce:1e:2e:69:
+ b6:b8:62:1a:a0:00:46:73:71:9e:d2:e7:cf:42:a8:
+ e3:7c:12:8f:06:da:d4:2f:87:e6:52:68:d9:8f:89:
+ d1:43:8c:5c:5f:a5:bd:6c:04:c6:fd:36:ee:f6:d2:
+ cd:15:f1:43:31:cc:20:e1:ee:8c:9e:3d:91:9d:28:
+ ff:85:d3:8f:8c:90:1d:1e:1d:64:8e:6c:1a:f3:b2:
+ 3b:23:29:5b:03:ff:97:d4:78:b6:dd:d5:27:4a:d4:
+ 2d:9c:2b:3b:28:45:0f:86:54:4c:8c:25:e8:88:48:
+ 59:55:d3:97:f1:74:06:52:c9:b3:dc:c0:7f:b7:6a:
+ 25:57:fb:b7:0c:f5:e9:3c:6e:e7:c8:7a:aa:c0:7d:
+ 95:5d:bc:ef:f6:16:eb:fa:59:f4:76:30:47:b7:d9:
+ 73:bf:f6:08:f4:d9:74:86:59:de:ac:3d:73:27:fe:
+ 57:e5:2a:f3:4d:28:45:82:51:67:6a:4c:0a:c6:8b:
+ 40:aa:43:80:fe:43:bd:eb:b9:42:2d:84:22:6b:fb:
+ b2:d6:2b:ee:d0:28:6f:7c:d1:ad:51:47:b1:99:26:
+ fb:37:b2:48:54:0e:1d:de:b9:ad:ae:20:23:e2:a9:
+ 02:e5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Cert Type:
+ SSL Server
+ Netscape Comment:
+ Easy-RSA Generated Server Certificate
+ X509v3 Subject Key Identifier:
+ 51:92:B6:A3:D7:D6:EC:8F:FC:16:C5:D4:0F:87:CC:EA:5C:7C:17:81
+ X509v3 Authority Key Identifier:
+ keyid:36:19:70:96:A9:5C:FE:A3:82:0F:79:95:31:52:2B:4A:41:BD:81:CB
+ DirName:/C=US/ST=CA/L=Cyberspace/O=LEAP Encryption Access Project/OU=cyberspace/CN=tests-leap.se/name=tests-leap/emailAddress=tests@leap.se
+ serial:8B:BF:41:63:1E:10:6A:EC
+
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication
+ X509v3 Key Usage:
+ Digital Signature, Key Encipherment
+ Signature Algorithm: sha1WithRSAEncryption
+ 88:d9:35:e0:d9:fa:fd:6b:57:e2:4d:f6:ef:91:6f:56:a6:2b:
+ 1a:1e:ec:8f:b0:18:e3:ec:ca:c9:1e:78:07:1d:0f:cf:fe:09:
+ 21:84:25:c4:27:ea:22:d7:48:53:73:ed:78:0f:42:5c:c7:f7:
+ 38:04:84:df:67:99:fd:75:6f:e8:dc:3b:91:ab:fa:c7:32:e5:
+ fd:3b:ce:de:7c:6a:df:39:46:1e:46:3a:4d:e1:e1:60:f3:bf:
+ aa:b2:0b:5d:ee:f2:0c:ee:82:7f:b5:02:75:04:47:d5:2b:c8:
+ e0:6d:6a:10:4a:ca:e0:c3:4f:ee:ff:15:71:37:f5:4d:95:38:
+ fe:a3:da:84:46:90:04:c2:61:86:a0:7f:e2:7d:62:46:6d:f6:
+ f8:90:51:88:c3:f2:8c:ca:b3:89:40:9f:6b:8b:33:65:e1:fd:
+ 0f:8b:d7:6a:93:dc:de:be:85:07:c7:d1:1d:b5:db:70:54:9f:
+ 95:d8:fb:11:f7:a7:e6:90:ba:9b:28:0e:3d:47:7a:63:6d:60:
+ 44:f6:96:aa:b6:a2:bc:0a:e5:25:c8:a2:74:91:54:95:bb:e2:
+ 09:01:56:73:6e:56:e8:6f:d6:a5:d8:18:96:c1:82:ef:2c:9e:
+ e2:4c:94:bc:00:71:5e:16:49:6b:e4:94:7a:d1:0c:2e:f4:19:
+ b2:2a:c2:b8
+-----BEGIN CERTIFICATE-----
+MIIFdDCCBFygAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBuDELMAkGA1UEBhMCVVMx
+CzAJBgNVBAgTAkNBMRMwEQYDVQQHEwpDeWJlcnNwYWNlMScwJQYDVQQKEx5MRUFQ
+IEVuY3J5cHRpb24gQWNjZXNzIFByb2plY3QxEzARBgNVBAsTCmN5YmVyc3BhY2Ux
+FjAUBgNVBAMTDXRlc3RzLWxlYXAuc2UxEzARBgNVBCkTCnRlc3RzLWxlYXAxHDAa
+BgkqhkiG9w0BCQEWDXRlc3RzQGxlYXAuc2UwHhcNMTMwOTAzMTc1MjE2WhcNMjMw
+OTAxMTc1MjE2WjCBtDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRMwEQYDVQQH
+EwpDeWJlcnNwYWNlMScwJQYDVQQKEx5MRUFQIEVuY3J5cHRpb24gQWNjZXNzIFBy
+b2plY3QxEzARBgNVBAsTCmN5YmVyc3BhY2UxEjAQBgNVBAMTCWxvY2FsaG9zdDET
+MBEGA1UEKRMKdGVzdHMtbGVhcDEcMBoGCSqGSIb3DQEJARYNdGVzdHNAbGVhcC5z
+ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMBPrtzzLg5Frqj+Cive
+ACi4kjpbpHtiU/POHi5ptrhiGqAARnNxntLnz0Ko43wSjwba1C+H5lJo2Y+J0UOM
+XF+lvWwExv027vbSzRXxQzHMIOHujJ49kZ0o/4XTj4yQHR4dZI5sGvOyOyMpWwP/
+l9R4tt3VJ0rULZwrOyhFD4ZUTIwl6IhIWVXTl/F0BlLJs9zAf7dqJVf7twz16Txu
+58h6qsB9lV287/YW6/pZ9HYwR7fZc7/2CPTZdIZZ3qw9cyf+V+Uq800oRYJRZ2pM
+CsaLQKpDgP5Dveu5Qi2EImv7stYr7tAob3zRrVFHsZkm+zeySFQOHd65ra4gI+Kp
+AuUCAwEAAaOCAYkwggGFMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZAMDQG
+CWCGSAGG+EIBDQQnFiVFYXN5LVJTQSBHZW5lcmF0ZWQgU2VydmVyIENlcnRpZmlj
+YXRlMB0GA1UdDgQWBBRRkraj19bsj/wWxdQPh8zqXHwXgTCB7QYDVR0jBIHlMIHi
+gBQ2GXCWqVz+o4IPeZUxUitKQb2By6GBvqSBuzCBuDELMAkGA1UEBhMCVVMxCzAJ
+BgNVBAgTAkNBMRMwEQYDVQQHEwpDeWJlcnNwYWNlMScwJQYDVQQKEx5MRUFQIEVu
+Y3J5cHRpb24gQWNjZXNzIFByb2plY3QxEzARBgNVBAsTCmN5YmVyc3BhY2UxFjAU
+BgNVBAMTDXRlc3RzLWxlYXAuc2UxEzARBgNVBCkTCnRlc3RzLWxlYXAxHDAaBgkq
+hkiG9w0BCQEWDXRlc3RzQGxlYXAuc2WCCQCLv0FjHhBq7DATBgNVHSUEDDAKBggr
+BgEFBQcDATALBgNVHQ8EBAMCBaAwDQYJKoZIhvcNAQEFBQADggEBAIjZNeDZ+v1r
+V+JN9u+Rb1amKxoe7I+wGOPsyskeeAcdD8/+CSGEJcQn6iLXSFNz7XgPQlzH9zgE
+hN9nmf11b+jcO5Gr+scy5f07zt58at85Rh5GOk3h4WDzv6qyC13u8gzugn+1AnUE
+R9UryOBtahBKyuDDT+7/FXE39U2VOP6j2oRGkATCYYagf+J9YkZt9viQUYjD8ozK
+s4lAn2uLM2Xh/Q+L12qT3N6+hQfH0R2123BUn5XY+xH3p+aQupsoDj1HemNtYET2
+lqq2orwK5SXIonSRVJW74gkBVnNuVuhv1qXYGJbBgu8snuJMlLwAcV4WSWvklHrR
+DC70GbIqwrg=
+-----END CERTIFICATE-----
diff --git a/tests/integration/bonafide/test_config.py b/tests/integration/bonafide/test_config.py
new file mode 100644
index 0000000..aeb2c84
--- /dev/null
+++ b/tests/integration/bonafide/test_config.py
@@ -0,0 +1,146 @@
+# -*- coding: utf-8 -*-
+# test_config.py
+# Copyright (C) 2015-2017 LEAP
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import os.path
+
+from BaseHTTPServer import BaseHTTPRequestHandler
+from twisted.internet import defer
+from twisted.trial import unittest
+
+from leap.bitmask.bonafide.config import Provider
+from leap.bitmask.bonafide.errors import NetworkError
+from leap.common.testing.basetest import BaseLeapTest
+from leap.common.testing.https_server import BaseHTTPSServerTestCase
+
+
+class ConfigTest(BaseHTTPSServerTestCase, unittest.TestCase, BaseLeapTest):
+
+ def setUp(self):
+ self.addr = Addr()
+ self.request_handler = request_handler(self.addr)
+ BaseHTTPSServerTestCase.setUp(self)
+ self.addr.host = 'localhost'
+ self.addr.port = self.PORT
+
+ def test_bootstrap_self_sign_cert_fails(self):
+ home = os.path.join(self.home, 'self_sign')
+ os.mkdir(home)
+ provider = Provider(self.addr.domain, autoconf=True, basedir=home)
+ d = provider.callWhenMainConfigReady(lambda: "Cert was accepted")
+ return self.assertFailure(d, NetworkError)
+
+ def test_bootstrap_pinned_cert(self):
+ cacert = os.path.join(os.path.dirname(__file__),
+ "cacert.pem")
+ home = os.path.join(self.home, 'pinned')
+ os.mkdir(home)
+ provider = Provider(self.addr.domain, autoconf=True, basedir=home,
+ cert_path=cacert)
+
+ def check_provider():
+ config = provider.config()
+ self.assertEqual(config["domain"], self.addr.host)
+ self.assertEqual(config["ca_cert_fingerprint"],
+ "SHA256: %s" % fingerprint)
+
+ provider.callWhenMainConfigReady(check_provider)
+ return defer.gatherResults([
+ provider.first_bootstrap[provider._domain],
+ provider.ongoing_bootstrap[provider._domain]])
+
+
+class Addr(object):
+ def __init__(self, host='localhost', port='4443'):
+ self.host = host
+ self.port = port
+
+ @property
+ def domain(self):
+ return "%s:%s" % (self.host, self.port)
+
+
+def request_handler(addr):
+ class RequestHandler(BaseHTTPRequestHandler):
+ def do_GET(self):
+ if self.path == '/provider.json':
+ body = provider_json % {
+ 'host': addr.host,
+ 'port': addr.port,
+ 'fingerprint': fingerprint
+ }
+
+ elif self.path == '/ca.crt':
+ cacert = os.path.join(os.path.dirname(__file__),
+ "leaptestscert.pem")
+ with open(cacert, 'r') as f:
+ castr = f.read()
+ body = castr
+
+ elif self.path == '/1/configs.json':
+ body = configs_json
+
+ else:
+ body = '{"error": "not implemented"}'
+
+ self.send_response(200)
+ self.send_header('Content-type', 'applicatino/json')
+ self.send_header('Content-Length', str(len(body)))
+ self.end_headers()
+ self.wfile.write(body)
+
+ return RequestHandler
+
+
+fingerprint = \
+ "cd0131b3352b7a29c307156b24f09fe862b1f5a2e55be7cd888048b91770f220"
+provider_json = """
+{
+ "api_uri": "https://%(host)s:%(port)s",
+ "api_version": "1",
+ "ca_cert_fingerprint": "SHA256: %(fingerprint)s",
+ "ca_cert_uri": "https://%(host)s:%(port)s/ca.crt",
+ "default_language": "en",
+ "description": {
+ "en": "example"
+ },
+ "domain": "%(host)s",
+ "enrollment_policy": "open",
+ "languages": [
+ "en"
+ ],
+ "name": {
+ "en": "Bitmask"
+ },
+ "service": {
+ "allow_anonymous": false,
+ "allow_free": true,
+ "allow_limited_bandwidth": false,
+ "allow_paid": false,
+ "allow_registration": true,
+ "allow_unlimited_bandwidth": true,
+ "bandwidth_limit": 102401,
+ "default_service_level": 1,
+ "levels": {
+ "1": {
+ "description": "hi.",
+ "name": "free"
+ }
+ }
+ },
+ "services": []
+}
+"""
+configs_json = "{}"