Prefer certifi provided certificates (#108)

Sets the SSL context to use the certifi provided root certificate bundle by default, unless the certifi module is older than a year.

If the system-provided root certificate bundle is empty, certifi certs are always loaded.
This commit is contained in:
Dpeta 2022-12-22 22:03:26 +01:00 committed by GitHub
parent 32c4b2ca40
commit afac304821
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -21,6 +21,7 @@ import ssl
import socket
import select
import logging
import datetime
import traceback
from oyoyo.parse import parse_raw_irc_command
@ -207,23 +208,35 @@ class IRCClient:
def get_ssl_context(self):
"""Returns an SSL context for connecting over SSL/TLS.
Loads the certifi certs instead of the system-provided certificates if
the system certificate store is empty."""
context = ssl.create_default_context()
# Check if store is empty
empty_cert_store = list(context.cert_store_stats().values()).count(0) == 3
if empty_cert_store and "certifi" in sys.modules:
# Can't validate certificates if store is empty,
# load root certificates from certifi instead.
context = ssl.create_default_context(cafile=certifi.where())
Loads the certifi root certificate bundle if the certifi module is less
than a year old or if the system certificate store is empty.
The cert store on Windows also seems to have issues, so it's better
to use the certifi provided bundle assuming it's a recent version.
On MacOS the system cert store is usually empty, as Python does not use
the system provided ones, instead relying on a bundle installed with the
python installer."""
default_context = ssl.create_default_context()
if "certifi" not in sys.modules:
return default_context
# Get age of certifi module
certifi_date = datetime.datetime.strptime(certifi.__version__, "%Y.%m.%d")
current_date = datetime.datetime.now()
certifi_age = current_date - certifi_date
empty_cert_store = (
list(default_context.cert_store_stats().values()).count(0) == 3
)
# 31557600 seconds is approximately 1 year
if empty_cert_store or certifi_age.total_seconds() <= 31557600:
PchumLog.info(
"Using SSL/TLS context with certifi-provided root certificates."
)
else:
PchumLog.info(
"Using SSL/TLS context with system-provided root certificates."
)
return context
return ssl.create_default_context(cafile=certifi.where())
PchumLog.info("Using SSL/TLS context with system-provided root certificates.")
return default_context
def connect(self, verify_hostname=True):
"""initiates the connection to the server set in self.host:self.port