codekingpro/portable-devtools
114k
1"""2`cryptography.x509 <https://github.com/pyca/cryptography>`_-specific code.3"""4 5from __future__ import annotations6 7import warnings8 9from typing import Sequence10 11from cryptography.x509 import (12 Certificate,13 DNSName,14 ExtensionOID,15 IPAddress,16 ObjectIdentifier,17 OtherName,18 UniformResourceIdentifier,19)20from cryptography.x509.extensions import ExtensionNotFound21from pyasn1.codec.der.decoder import decode22from pyasn1.type.char import IA5String23 24from .exceptions import CertificateError25from .hazmat import (26 DNS_ID,27 CertificatePattern,28 DNSPattern,29 IPAddress_ID,30 IPAddressPattern,31 SRVPattern,32 URIPattern,33 verify_service_identity,34)35 36 37__all__ = ["verify_certificate_hostname"]38 39 40def verify_certificate_hostname(41 certificate: Certificate, hostname: str42) -> None:43 r"""44 Verify whether *certificate* is valid for *hostname*.45 46 .. note::47 Nothing is verified about the *authority* of the certificate;48 the caller must verify that the certificate chains to an appropriate49 trust root themselves.50 51 Args:52 certificate: A *cryptography* X509 certificate object.53 54 hostname: The hostname that *certificate* should be valid for.55 56 Raises:57 service_identity.VerificationError:58 If *certificate* is not valid for *hostname*.59 60 service_identity.CertificateError:61 If *certificate* contains invalid / unexpected data. This includes62 the case where the certificate contains no `subjectAltName`\ s.63 64 .. versionchanged:: 24.1.065 :exc:`~service_identity.CertificateError` is raised if the certificate66 contains no ``subjectAltName``\ s instead of67 :exc:`~service_identity.VerificationError`.68 """69 verify_service_identity(70 cert_patterns=extract_patterns(certificate),71 obligatory_ids=[DNS_ID(hostname)],72 optional_ids=[],73 )74 75 76def verify_certificate_ip_address(77 certificate: Certificate, ip_address: str78) -> None:79 r"""80 Verify whether *certificate* is valid for *ip_address*.81 82 .. note::83 Nothing is verified about the *authority* of the certificate;84 the caller must verify that the certificate chains to an appropriate85 trust root themselves.86 87 Args:88 certificate: A *cryptography* X509 certificate object.89 90 ip_address:91 The IP address that *connection* should be valid for. Can be an92 IPv4 or IPv6 address.93 94 Raises:95 service_identity.VerificationError:96 If *certificate* is not valid for *ip_address*.97 98 service_identity.CertificateError:99 If *certificate* contains invalid / unexpected data. This includes100 the case where the certificate contains no ``subjectAltName``\ s.101 102 .. versionadded:: 18.1.0103 104 .. versionchanged:: 24.1.0105 :exc:`~service_identity.CertificateError` is raised if the certificate106 contains no ``subjectAltName``\ s instead of107 :exc:`~service_identity.VerificationError`.108 """109 verify_service_identity(110 cert_patterns=extract_patterns(certificate),111 obligatory_ids=[IPAddress_ID(ip_address)],112 optional_ids=[],113 )114 115 116ID_ON_DNS_SRV = ObjectIdentifier("1.3.6.1.5.5.7.8.7") # id_on_dnsSRV117 118 119def extract_patterns(cert: Certificate) -> Sequence[CertificatePattern]:120 """121 Extract all valid ID patterns from a certificate for service verification.122 123 Args:124 cert: The certificate to be dissected.125 126 Returns:127 List of IDs.128 129 .. versionchanged:: 23.1.0130 ``commonName`` is not used as a fallback anymore.131 """132 ids: list[CertificatePattern] = []133 try:134 ext = cert.extensions.get_extension_for_oid(135 ExtensionOID.SUBJECT_ALTERNATIVE_NAME136 )137 except ExtensionNotFound:138 pass139 else:140 ids.extend(141 [142 DNSPattern.from_bytes(name.encode("utf-8"))143 for name in ext.value.get_values_for_type(DNSName)144 ]145 )146 ids.extend(147 [148 URIPattern.from_bytes(uri.encode("utf-8"))149 for uri in ext.value.get_values_for_type(150 UniformResourceIdentifier151 )152 ]153 )154 ids.extend(155 [156 IPAddressPattern(ip)157 for ip in ext.value.get_values_for_type(IPAddress)158 ]159 )160 for other in ext.value.get_values_for_type(OtherName):161 if other.type_id == ID_ON_DNS_SRV:162 srv, _ = decode(other.value)163 if isinstance(srv, IA5String):164 ids.append(SRVPattern.from_bytes(srv.asOctets()))165 else: # pragma: no cover166 msg = "Unexpected certificate content."167 raise CertificateError(msg)168 169 return ids170 171 172def extract_ids(cert: Certificate) -> Sequence[CertificatePattern]:173 """174 Deprecated and never public API. Use :func:`extract_patterns` instead.175 176 .. deprecated:: 23.1.0177 """178 warnings.warn(179 category=DeprecationWarning,180 message="`extract_ids()` is deprecated, please use `extract_patterns()`.",181 stacklevel=2,182 )183 return extract_patterns(cert)184 