From a8d15eb24062d6f1bc05cc5f32bf22178ca91f4a Mon Sep 17 00:00:00 2001 From: Sean Whalen Date: Mon, 28 Oct 2024 20:27:22 -0400 Subject: [PATCH] 5.7.1 - Properly parse a certificate SAN - Certificate warnings fire properly --- CHANGELOG.md | 6 ++++++ checkdmarc/_constants.py | 2 +- checkdmarc/bimi.py | 26 +++++++++++++------------- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9927358..8b7fec3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ Changelog ========= +7.5.1 +----- + +- Properly parse a certificate SAN +- Certificate warnings fire properly + 5.7.0 ----- diff --git a/checkdmarc/_constants.py b/checkdmarc/_constants.py index f6cc43a..08024c4 100644 --- a/checkdmarc/_constants.py +++ b/checkdmarc/_constants.py @@ -18,7 +18,7 @@ See the License for the specific language governing permissions and limitations under the License.""" -__version__ = "5.7.0" +__version__ = "5.7.1" OS = platform.system() OS_RELEASE = platform.release() diff --git a/checkdmarc/bimi.py b/checkdmarc/bimi.py index 868eb61..5bfdf10 100644 --- a/checkdmarc/bimi.py +++ b/checkdmarc/bimi.py @@ -227,18 +227,17 @@ def check_svg_requirements(svg_metadata: OrderedDict) -> [str]: return _warnings -def _get_certificate_subjecttaltnames(cert: Union[X509, bytes]) -> [str]: +def _get_certificate_san(cert: Union[X509, bytes]) -> [str]: """Get the subjectaltname from a PEM certificate""" if type(cert) is bytes: cert = load_certificate(FILETYPE_PEM, cert) for cert_ext_id in range(cert.get_extension_count()): cert_ext = cert.get_extension(cert_ext_id) if cert_ext.get_short_name() == b"subjectAltName": - ext_data = ( - cert_ext.get_data().strip(b"0\x10\x82\x0e").strip(b"0\x81\x8e\x82\x13") - ) - return ext_data.decode("utf-8", errors="ignore").lower().split("\x82\x15") - + san = cert_ext.__str__() + san.replace("DNS:", "") + san = san.split(", ") + return san def extract_logo_from_certificate(cert: Union[bytes, X509]): """Extracts the logo from a certificate""" @@ -258,7 +257,7 @@ def get_certificate_metadata(pem_crt: Union[str, bytes], domain=None) -> Ordered metadata = OrderedDict() valid = False validation_errors = [] - subjectaltnames = [] + san = [] def decode_components(components: dict): new_dict = OrderedDict() @@ -281,8 +280,8 @@ def decode_components(components: dict): metadata["serial_number"] = vmc.get_serial_number() metadata["expires"] = str(vmc.get_notAfter()) metadata["valid"] = valid and not vmc.has_expired() - subjectaltnames = _get_certificate_subjecttaltnames(vmc) - metadata["domains"] = subjectaltnames + san = _get_certificate_san(vmc) + metadata["domains"] = san metadata["logodata_sha256_hash"] = None logodata = extract_logo_from_certificate(vmc) if logodata is not None: @@ -298,9 +297,9 @@ def decode_components(components: dict): except Exception as e: validation_errors.append(str(e)) if domain is not None: - if domain.lower() not in subjectaltnames: + if domain.lower() not in san: validation_errors.append( - f"{domain} does not match the certificate subjectaltnames, {subjectaltnames}" + f"{domain} does not match the certificate san, {san}" ) metadata["validation_errors"] = validation_errors metadata["valid"] = False @@ -565,18 +564,19 @@ def parse_bimi_record( response.raise_for_status() pem_bytes = response.content cert_metadata = get_certificate_metadata(pem_bytes, domain=domain) + hash_match = False if ( image_metadata["sha256_hash"] == cert_metadata["logodata_sha256_hash"] ): - certificate_provided = True + hash_match = True else: warnings.append( "SHA256 hash mismatch between the certificate and the image" ) except Exception as e: warnings.append(f"Unable to download mark certificate - {str(e)}") - + certificate_provided == hash_match and cert_metadata["valid"] if not certificate_provided: warnings.append( "Most providers will not display a BIMI image without a valid mark certificate"