Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Let's Encrypt certificates provided for freeboxos.fr domains #1

Merged

Conversation

pdecat
Copy link

@pdecat pdecat commented Jun 17, 2018

This official way to get HTTPS support without providing a custom CA certificate when connecting to the Freebox API is to setup a custom freeboxos.fr subdomain: https://dev.freebox.fr/bugs/task/19630

Without this change, accessing mycustomdomain.freeboxos.fr:54321 from Home Assistant fails with the following error:

home-assistant   | 2018-06-17 13:51:45 ERROR (MainThread) [homeassistant.core] Error doing job: <uvloop.loop.SSLProtocol object at 0x7f15e825c7f0>: SSL handshake failed
home-assistant   | Traceback (most recent call last):
home-assistant   |   File "uvloop/sslproto.pyx", line 592, in uvloop.loop.SSLProtocol._on_handshake_complete
home-assistant   |   File "uvloop/sslproto.pyx", line 171, in uvloop.loop._SSLPipe.feed_ssldata
home-assistant   |   File "/usr/local/lib/python3.6/ssl.py", line 689, in do_handshake
home-assistant   |     self._sslobj.do_handshake()
home-assistant   | ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:833)
home-assistant   | 2018-06-17 13:51:45 ERROR (MainThread) [homeassistant.core] Error doing job: <uvloop.loop.SSLProtocol object at 0x7f15e825c7f0>: SSL error errno:1 reason: CERTIFICATE_VERIFY_FAILED
home-assistant   | Traceback (most recent call last):
home-assistant   |   File "uvloop/sslproto.pyx", line 496, in uvloop.loop.SSLProtocol.data_received
home-assistant   |   File "uvloop/sslproto.pyx", line 204, in uvloop.loop._SSLPipe.feed_ssldata
home-assistant   |   File "uvloop/sslproto.pyx", line 171, in uvloop.loop._SSLPipe.feed_ssldata
home-assistant   |   File "/usr/local/lib/python3.6/ssl.py", line 689, in do_handshake
home-assistant   |     self._sslobj.do_handshake()
home-assistant   | ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:833)
home-assistant   | 2018-06-17 13:51:45 ERROR (MainThread) [homeassistant.components.device_tracker] Error setting up platform freebox
home-assistant   | Traceback (most recent call last):
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiohttp/connector.py", line 822, in _wrap_create_connection
home-assistant   |     return await self._loop.create_connection(*args, **kwargs)
home-assistant   |   File "uvloop/loop.pyx", line 1811, in create_connection
home-assistant   |   File "uvloop/loop.pyx", line 1789, in uvloop.loop.Loop.create_connection
home-assistant   |   File "uvloop/handles/tcp.pyx", line 178, in uvloop.loop.TCPTransport.connect
home-assistant   |   File "uvloop/handles/tcp.pyx", line 200, in uvloop.loop._TCPConnectRequest.connect
home-assistant   | OSError: [Errno 101] Network is unreachable
home-assistant   |
home-assistant   | The above exception was the direct cause of the following exception:
home-assistant   |
home-assistant   | Traceback (most recent call last):
home-assistant   |   File "/usr/src/app/homeassistant/components/device_tracker/__init__.py", line 179, in async_setup_platform
home-assistant   |     hass, p_config, tracker.async_see, disc_info)
home-assistant   |   File "/usr/src/app/homeassistant/components/device_tracker/freebox.py", line 51, in async_setup_scanner
home-assistant   |     await scanner.async_start(hass, interval)
home-assistant   |   File "/usr/src/app/homeassistant/components/device_tracker/freebox.py", line 96, in async_start
home-assistant   |     await self.async_update_info()
home-assistant   |   File "/usr/src/app/homeassistant/components/device_tracker/freebox.py", line 106, in async_update_info
home-assistant   |     await self.fbx.open(self.host, self.port)
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiofreepybox/aiofreepybox.py", line 63, in open
home-assistant   |     self._access = await self._get_freebox_access(host, port, self.api_version, self.token_file, self.app_desc, self.timeout)
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiofreepybox/aiofreepybox.py", line 100, in _get_freebox_access
home-assistant   |     app_token, track_id = await self._get_app_token(base_url, app_desc, timeout)
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiofreepybox/aiofreepybox.py", line 164, in _get_app_token
home-assistant   |     r = await self.session.post(url, data=data, timeout=timeout)
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiohttp/client.py", line 366, in _request
home-assistant   |     timeout=timeout
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiohttp/connector.py", line 445, in connect
home-assistant   |     proto = await self._create_connection(req, traces, timeout)
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiohttp/connector.py", line 757, in _create_connection
home-assistant   |     req, traces, timeout)
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiohttp/connector.py", line 879, in _create_direct_connection
home-assistant   |     raise last_exc
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiohttp/connector.py", line 862, in _create_direct_connection
home-assistant   |     req=req, client_error=client_error)
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiohttp/connector.py", line 829, in _wrap_create_connection
home-assistant   |     raise client_error(req.connection_key, exc) from exc
home-assistant   | aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host mycustomdomain.freeboxos.fr:54321 ssl:None [Network is unreachable]

Note: using a custom domain does not work with discovery and requires adding configuration:

device_tracker:
  - platform: freebox
    host: mycustomdomain.freeboxos.fr
    port: 54321

Tested with Home Assistant 0.72.0b2 (homeassistant/home-assistant:0.72.0b2 docker image)

@pdecat
Copy link
Author

pdecat commented Jun 17, 2018

Please note that I've gone this way because the discovered endpoint does not work because of SSL issues:

home-assistant   | 2018-06-17 17:37:00 INFO (MainThread) [homeassistant.components.discovery] Found new service: freebox {'host': '192.168.1.1', 'port': 80, 'hostname': 'Freebox-Server.local.', 'properties': {'api_version': '5.0', 'device_type': 'FreeboxServer1,1', 'api_base_url': '/api/', 'uid': '1234567890d7db59fd845de230615c92', 'https_available': '1', 'https_port': '54321', 'api_domain': 'abcdefg.fbxos.fr'}}
home-assistant   | 2018-06-17 17:37:00 INFO (MainThread) [homeassistant.core] Bus:Handling <Event platform_discovered[L]: service=load_platform.device_tracker, platform=freebox, discovered=host=192.168.1.1, port=80, hostname=Freebox-Server.local., properties=api_version=5.0, device_type=FreeboxServer1,1, api
_base_url=/api/, uid=1234567890d7db59fd845de230615c92, https_available=1, https_port=54321, api_domain=abcdefg.fbxos.fr>
home-assistant   | 2018-06-17 17:37:00 INFO (MainThread) [homeassistant.components.device_tracker] Setting up device_tracker.freebox
home-assistant   | 2018-06-17 17:37:00 INFO (MainThread) [homeassistant.components.device_tracker.freebox] Discovered Freebox server: abcdefg.fbxos.fr:54321
home-assistant   | 2018-06-17 17:37:00 INFO (MainThread) [homeassistant.components.device_tracker.freebox] Scanning devices
home-assistant   | 2018-06-17 17:37:00 INFO (MainThread) [aiofreepybox.aiofreepybox] Read application authorization file
home-assistant   | 2018-06-17 17:37:01 ERROR (MainThread) [homeassistant.core] Error doing job: <uvloop.loop.SSLProtocol object at 0x7fc2900cbb38>: SSL handshake failed
home-assistant   | Traceback (most recent call last):
home-assistant   |   File "uvloop/sslproto.pyx", line 592, in uvloop.loop.SSLProtocol._on_handshake_complete
home-assistant   |   File "uvloop/sslproto.pyx", line 171, in uvloop.loop._SSLPipe.feed_ssldata
home-assistant   |   File "/usr/local/lib/python3.6/ssl.py", line 689, in do_handshake
home-assistant   |     self._sslobj.do_handshake()
home-assistant   | ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:833)
home-assistant   | 2018-06-17 17:37:01 ERROR (MainThread) [homeassistant.core] Error doing job: <uvloop.loop.SSLProtocol object at 0x7fc2900cbb38>: SSL error errno:1 reason: CERTIFICATE_VERIFY_FAILED
home-assistant   | Traceback (most recent call last):
home-assistant   |   File "uvloop/sslproto.pyx", line 496, in uvloop.loop.SSLProtocol.data_received
home-assistant   |   File "uvloop/sslproto.pyx", line 204, in uvloop.loop._SSLPipe.feed_ssldata
home-assistant   |   File "uvloop/sslproto.pyx", line 171, in uvloop.loop._SSLPipe.feed_ssldata
home-assistant   |   File "/usr/local/lib/python3.6/ssl.py", line 689, in do_handshake
home-assistant   |     self._sslobj.do_handshake()
home-assistant   | ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:833)
home-assistant   | 2018-06-17 17:37:01 ERROR (MainThread) [homeassistant.components.device_tracker] Error setting up platform freebox
home-assistant   | Traceback (most recent call last):
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiohttp/connector.py", line 822, in _wrap_create_connection
home-assistant   |     return await self._loop.create_connection(*args, **kwargs)
home-assistant   |   File "uvloop/loop.pyx", line 1811, in create_connection
home-assistant   |   File "uvloop/loop.pyx", line 1789, in uvloop.loop.Loop.create_connection
home-assistant   |   File "uvloop/handles/tcp.pyx", line 178, in uvloop.loop.TCPTransport.connect
home-assistant   |   File "uvloop/handles/tcp.pyx", line 200, in uvloop.loop._TCPConnectRequest.connect
home-assistant   | OSError: [Errno 101] Network is unreachable
home-assistant   |
home-assistant   | The above exception was the direct cause of the following exception:
home-assistant   |
home-assistant   | Traceback (most recent call last):
home-assistant   |   File "/usr/src/app/homeassistant/components/device_tracker/__init__.py", line 179, in async_setup_platform
home-assistant   |     hass, p_config, tracker.async_see, disc_info)
home-assistant   |   File "/usr/src/app/homeassistant/components/device_tracker/freebox.py", line 51, in async_setup_scanner
home-assistant   |     await scanner.async_start(hass, interval)
home-assistant   |   File "/usr/src/app/homeassistant/components/device_tracker/freebox.py", line 96, in async_start
home-assistant   |     await self.async_update_info()
home-assistant   |   File "/usr/src/app/homeassistant/components/device_tracker/freebox.py", line 106, in async_update_info
home-assistant   |     await self.fbx.open(self.host, self.port)
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiofreepybox/aiofreepybox.py", line 67, in open
home-assistant   |     self._access = await self._get_freebox_access(host, port, self.api_version, self.token_file, self.app_desc, self.timeout)
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiofreepybox/aiofreepybox.py", line 135, in _get_freebox_access
home-assistant   |     session_token, session_permissions = await self._get_session_token(base_url, app_token, app_desc['app_id'], timeout)
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiofreepybox/aiofreepybox.py", line 212, in _get_session_token
home-assistant   |     challenge = await self._get_challenge(base_url, timeout)
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiofreepybox/aiofreepybox.py", line 237, in _get_challenge
home-assistant   |     r = await self.session.get(url, timeout=timeout)
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiohttp/client.py", line 366, in _request
home-assistant   |     timeout=timeout
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiohttp/connector.py", line 445, in connect
home-assistant   |     proto = await self._create_connection(req, traces, timeout)
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiohttp/connector.py", line 757, in _create_connection
home-assistant   |     req, traces, timeout)
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiohttp/connector.py", line 879, in _create_direct_connection
home-assistant   |     raise last_exc
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiohttp/connector.py", line 862, in _create_direct_connection
home-assistant   |     req=req, client_error=client_error)
home-assistant   |   File "/usr/local/lib/python3.6/site-packages/aiohttp/connector.py", line 829, in _wrap_create_connection
home-assistant   |     raise client_error(req.connection_key, exc) from exc
home-assistant   | aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host abcdefg.fbxos.fr:54321 ssl:None [Network is unreachable]
home-assistant   | 2018-06-17 17:37:01 ERROR (SyncWorker_31) [homeassistant.core] Error doing job: Unclosed client session

@stilllman
Copy link

Didn't know about this feature of the Freebox, thanks. I'll merge your PR so that custom subdomains can be used, but I'll need to make sure the default one works as well. As far as I understand the documentation, the default certificate can be validated by trusting the Freebox CA, so I suppose I must have misused python.ssl.

@stilllman stilllman merged commit 6442cfa into hacf-fr:aiofreepybox Jun 19, 2018
@@ -54,9 +54,13 @@ def __init__(self, app_desc=app_desc, token_file=token_file, api_version='v3', t
if not self._is_app_desc_valid(self.app_desc):
raise InvalidTokenError('invalid application descriptor')

cert_path = os.path.join(os.path.dirname(__file__), 'freebox_root_ca.pem')
if host.endswith('.freeboxos.fr'):
Copy link
Author

@pdecat pdecat Jun 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought, I'm thinking about reversing the check to only use the freebox_root_ca.pem CA for fbxos.fr subdomains.

What do you think?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking the same thing, it is possible to configure a fully custom domain name that does not necessarily end in freeboxos.fr. I even wonder if testing domains is really a good idea, perhaps it would be better to simply register the Free certificates as trusted authorities and always use the default SSL context creation. I'm not sure exactly yet how to do that, I'll do some tests.

By the way, I didn't manage to reproduce issue #2 at home. What Freebox do you have? If I continue failing to reproduce, would you be willing to perform some tests if I push a PR?

Copy link
Author

@pdecat pdecat Jun 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not fond of trusting custom CAs as you lose all the security work done upstream by the distribution.

I have a Freebox v6 r1 from july 2011 (the one from december 2010 broke and was exchanged), current firmware version 3.5.2.

Open for testing.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm not sure I understand: the CA would only be trusted in the context of the library, what would be the risk? (sorry if that's a dumb question, I'm pretty much discovering SSL as we're speaking!)

If trusting the Freebox CA is a security risk, perhaps we could make it optional so that the user can decide whether she wants to enable insecure access or not, instead of relying on the domain used. I guess this parameter would need to be propagated to Home Assistant as well, but it would make the setup more complex, and prevent automatic discovery to work correctly.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's continue this discussion on PR #3

@pdecat pdecat deleted the letencrypt_support_freeboxos.fr branch June 22, 2018 23:37
stilllman added a commit to stilllman/home-assistant that referenced this pull request Jun 23, 2018
The previous version of aiofreepybox was not working with custom
domain names, which uses a Let's Encrypt certificates. Also, it
was not working with the default domain name when connecting to
Freebox v6. This should be fixed in aiofreepybox 0.0.4.

See hacf-fr/freebox-api#1,
hacf-fr/freebox-api#3 and
hacf-fr/freebox-api#2 for more info.
balloob pushed a commit to home-assistant/core that referenced this pull request Jun 25, 2018
The previous version of aiofreepybox was not working with custom
domain names, which uses a Let's Encrypt certificates. Also, it
was not working with the default domain name when connecting to
Freebox v6. This should be fixed in aiofreepybox 0.0.4.

See hacf-fr/freebox-api#1,
hacf-fr/freebox-api#3 and
hacf-fr/freebox-api#2 for more info.
eavanvalkenburg pushed a commit to eavanvalkenburg/home-assistant that referenced this pull request Jun 28, 2018
)

The previous version of aiofreepybox was not working with custom
domain names, which uses a Let's Encrypt certificates. Also, it
was not working with the default domain name when connecting to
Freebox v6. This should be fixed in aiofreepybox 0.0.4.

See hacf-fr/freebox-api#1,
hacf-fr/freebox-api#3 and
hacf-fr/freebox-api#2 for more info.
girlpunk pushed a commit to girlpunk/home-assistant that referenced this pull request Sep 4, 2018
)

The previous version of aiofreepybox was not working with custom
domain names, which uses a Let's Encrypt certificates. Also, it
was not working with the default domain name when connecting to
Freebox v6. This should be fixed in aiofreepybox 0.0.4.

See hacf-fr/freebox-api#1,
hacf-fr/freebox-api#3 and
hacf-fr/freebox-api#2 for more info.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants