2019-08-28 17:35:09 +00:00
|
|
|
"""Helper functions for the Cert Expiry platform."""
|
|
|
|
import socket
|
|
|
|
import ssl
|
|
|
|
|
2020-06-18 16:29:46 +00:00
|
|
|
from homeassistant.util import dt
|
|
|
|
|
2019-08-28 17:35:09 +00:00
|
|
|
from .const import TIMEOUT
|
2020-03-02 13:44:24 +00:00
|
|
|
from .errors import (
|
|
|
|
ConnectionRefused,
|
|
|
|
ConnectionTimeout,
|
|
|
|
ResolveFailed,
|
|
|
|
ValidationFailure,
|
|
|
|
)
|
2019-08-28 17:35:09 +00:00
|
|
|
|
|
|
|
|
|
|
|
def get_cert(host, port):
|
2020-03-02 13:44:24 +00:00
|
|
|
"""Get the certificate for the host and port combination."""
|
2019-08-28 17:35:09 +00:00
|
|
|
ctx = ssl.create_default_context()
|
|
|
|
address = (host, port)
|
|
|
|
with socket.create_connection(address, timeout=TIMEOUT) as sock:
|
|
|
|
with ctx.wrap_socket(sock, server_hostname=address[0]) as ssock:
|
2019-10-07 15:17:39 +00:00
|
|
|
# pylint disable: https://github.com/PyCQA/pylint/issues/3166
|
|
|
|
cert = ssock.getpeercert() # pylint: disable=no-member
|
2019-08-28 17:35:09 +00:00
|
|
|
return cert
|
2020-03-02 13:44:24 +00:00
|
|
|
|
|
|
|
|
2020-06-18 16:29:46 +00:00
|
|
|
async def get_cert_expiry_timestamp(hass, hostname, port):
|
|
|
|
"""Return the certificate's expiration timestamp."""
|
2020-03-02 13:44:24 +00:00
|
|
|
try:
|
|
|
|
cert = await hass.async_add_executor_job(get_cert, hostname, port)
|
2020-08-28 11:50:32 +00:00
|
|
|
except socket.gaierror as err:
|
|
|
|
raise ResolveFailed(f"Cannot resolve hostname: {hostname}") from err
|
|
|
|
except socket.timeout as err:
|
|
|
|
raise ConnectionTimeout(
|
|
|
|
f"Connection timeout with server: {hostname}:{port}"
|
|
|
|
) from err
|
|
|
|
except ConnectionRefusedError as err:
|
|
|
|
raise ConnectionRefused(
|
|
|
|
f"Connection refused by server: {hostname}:{port}"
|
|
|
|
) from err
|
2020-03-02 13:44:24 +00:00
|
|
|
except ssl.CertificateError as err:
|
2020-08-28 11:50:32 +00:00
|
|
|
raise ValidationFailure(err.verify_message) from err
|
2020-03-02 13:44:24 +00:00
|
|
|
except ssl.SSLError as err:
|
2020-08-28 11:50:32 +00:00
|
|
|
raise ValidationFailure(err.args[0]) from err
|
2020-03-02 13:44:24 +00:00
|
|
|
|
|
|
|
ts_seconds = ssl.cert_time_to_seconds(cert["notAfter"])
|
2020-06-18 16:29:46 +00:00
|
|
|
return dt.utc_from_timestamp(ts_seconds)
|