-
Notifications
You must be signed in to change notification settings - Fork 13
Description
The problem
The documentation mentions that the hostname in the SSL verification should be of the form appliance/p1dongle/5c2fafaabbcc. See https://api-documentation.homewizard.com/docs/v2/authorization#hostname-validation
It would be useful to document the difference between the commonName and the DNS name. Some tools use the former, other the latter.
Additional information
One can use the following Python snippet to get both names for one's device:
import ssl
import socket
from pprint import pprint
context = ssl.create_default_context()
context.load_verify_locations('homewizard-ca-cert.pem')
context.check_hostname = False
with socket.create_connection(("192.168.1.100", 443)) as sock:
with context.wrap_socket(sock, server_hostname="192.168.1.100") as ssock:
cert = ssock.getpeercert()
pprint(cert)This gives for example:
{'issuer': ((('countryName', 'NL'),),
(('stateOrProvinceName', 'ZH'),),
(('organizationName', 'HomeWizard'),),
(('commonName', 'Appliance Access CA'),)),
'notAfter': 'Dec 31 23:59:59 2049 GMT',
'notBefore': 'Jan 1 00:00:00 2025 GMT',
'serialNumber': '5C2FAFAABBCC',
'subject': ((('commonName', 'appliance/p1dongle/5c2fafaabbcc'),),),
'subjectAltName': (('DNS', '5c2fafaabbcc.p1dongle.device.homewizard.energy'),),
'version': 3}With this information, one can perform SSL verificatoin with cURL:
curl https://5c2fafaabbcc.p1dongle.device.homewizard.energy/api/user \
--resolve 5c2fafaabbcc.p1dongle.device.homewizard.energy:443:192.168.1.100 \
--cacert homewizard-ca-cert.pem(The documentation claims cURL cannot do this, but this seems to work.)
Similarly, if one prefers to use the requests library (convenient for simple synchronous scripting), the following can be used:
import requests
import ssl
from requests.adapters import HTTPAdapter
from urllib.parse import urlparse
class SSLHostAdapter(HTTPAdapter):
"""Inject hostname for SSL verification."""
def __init__(self, *, hostmap, cafile: str, **kwargs):
self.hostmap = hostmap
self.ssl_context = ssl.create_default_context(cafile=cafile)
self.ssl_context.hostname_checks_common_name = True
super().__init__(**kwargs)
def init_poolmanager(self, *args, **kwargs):
kwargs['ssl_context'] = self.ssl_context
return super().init_poolmanager(*args, **kwargs)
def get_connection_with_tls_context(self, request, verify, proxies=None, cert=None):
conn = super().get_connection_with_tls_context(request, verify, proxies, cert)
conn.assert_hostname = self.hostmap[urlparse(request.url).hostname]
return conn
adapter = SSLHostAdapter(
hostmap={'192.168.1.100': '5c2fafaabbcc.p1dongle.device.homewizard.energy'},
cafile='homewizard-ca-cert.pem'
)
session = requests.Session()
session.mount('https://', adapter)
response = session.get('https://192.168.1.100/api/user')
print(response.text)I admit, the adapter is a little hacky, but works quite well.