from _sha256 import sha256
from typing import List, cast

from cryptography import x509
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
from cryptography.x509 import ExtensionOID, DNSName, ExtensionNotFound, NameOID


def extract_dns_subject_alternative_names(certificate: x509.Certificate) -> List[str]:
    """Retrieve all the DNS entries of the Subject Alternative Name extension.
    """
    subj_alt_names: List[str] = []
    try:
        san_ext = certificate.extensions.get_extension_for_oid(ExtensionOID.SUBJECT_ALTERNATIVE_NAME)
        san_ext_value = cast(x509.SubjectAlternativeName, san_ext.value)
        subj_alt_names = san_ext_value.get_values_for_type(DNSName)
    except ExtensionNotFound:
        pass
    return subj_alt_names


def get_common_names(name_field: x509.Name) -> List[str]:
    return [cn.value for cn in name_field.get_attributes_for_oid(NameOID.COMMON_NAME)]


def get_public_key_sha256(certificate: x509.Certificate) -> bytes:
    pub_bytes = certificate.public_key().public_bytes(encoding=Encoding.DER, format=PublicFormat.SubjectPublicKeyInfo)
    digest = sha256(pub_bytes).digest()
    return digest

@@ -241,16 +241,76 @@
 NameOID%0A
+from cryptography.x509.extensions import DuplicateExtension%0A
 %0A%0Adef ex
@@ -807,16 +807,335 @@
    pass%0A
+    except DuplicateExtension:%0A        # Fix for https://github.com/nabla-c0d3/sslyze/issues/420%0A        # Not sure how browsers behave in this case but having a duplicate extension makes the certificate invalid%0A        # so we just return no SANs (likely to make hostname validation fail, which is fine)%0A        pass%0A%0A
     retu

Handle certificates with duplicate extensions