Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cryptography.py 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. """
  2. `cryptography.x509 <https://github.com/pyca/cryptography>`_-specific code.
  3. """
  4. from __future__ import annotations
  5. import warnings
  6. from typing import Sequence
  7. from cryptography.x509 import (
  8. Certificate,
  9. DNSName,
  10. ExtensionOID,
  11. IPAddress,
  12. ObjectIdentifier,
  13. OtherName,
  14. UniformResourceIdentifier,
  15. )
  16. from cryptography.x509.extensions import ExtensionNotFound
  17. from pyasn1.codec.der.decoder import decode
  18. from pyasn1.type.char import IA5String
  19. from .exceptions import CertificateError
  20. from .hazmat import (
  21. DNS_ID,
  22. CertificatePattern,
  23. DNSPattern,
  24. IPAddress_ID,
  25. IPAddressPattern,
  26. SRVPattern,
  27. URIPattern,
  28. verify_service_identity,
  29. )
  30. __all__ = ["verify_certificate_hostname"]
  31. def verify_certificate_hostname(
  32. certificate: Certificate, hostname: str
  33. ) -> None:
  34. """
  35. Verify whether *certificate* is valid for *hostname*.
  36. .. note:: Nothing is verified about the *authority* of the certificate;
  37. the caller must verify that the certificate chains to an appropriate
  38. trust root themselves.
  39. :param certificate: A *cryptography* X509 certificate object.
  40. :param hostname: The hostname that *certificate* should be valid for.
  41. :raises service_identity.VerificationError: If *certificate* is not valid
  42. for *hostname*.
  43. :raises service_identity.CertificateError: If *certificate* contains
  44. invalid / unexpected data.
  45. :returns: ``None``
  46. """
  47. verify_service_identity(
  48. cert_patterns=extract_patterns(certificate),
  49. obligatory_ids=[DNS_ID(hostname)],
  50. optional_ids=[],
  51. )
  52. def verify_certificate_ip_address(
  53. certificate: Certificate, ip_address: str
  54. ) -> None:
  55. """
  56. Verify whether *certificate* is valid for *ip_address*.
  57. .. note:: Nothing is verified about the *authority* of the certificate;
  58. the caller must verify that the certificate chains to an appropriate
  59. trust root themselves.
  60. :param certificate: A *cryptography* X509 certificate object.
  61. :param ip_address: The IP address that *connection* should be valid
  62. for. Can be an IPv4 or IPv6 address.
  63. :raises service_identity.VerificationError: If *certificate* is not valid
  64. for *ip_address*.
  65. :raises service_identity.CertificateError: If *certificate* contains
  66. invalid / unexpected data.
  67. :returns: ``None``
  68. .. versionadded:: 18.1.0
  69. """
  70. verify_service_identity(
  71. cert_patterns=extract_patterns(certificate),
  72. obligatory_ids=[IPAddress_ID(ip_address)],
  73. optional_ids=[],
  74. )
  75. ID_ON_DNS_SRV = ObjectIdentifier("1.3.6.1.5.5.7.8.7") # id_on_dnsSRV
  76. def extract_patterns(cert: Certificate) -> Sequence[CertificatePattern]:
  77. """
  78. Extract all valid ID patterns from a certificate for service verification.
  79. :param cert: The certificate to be dissected.
  80. :return: List of IDs.
  81. .. versionchanged:: 23.1.0
  82. ``commonName`` is not used as a fallback anymore.
  83. """
  84. ids: list[CertificatePattern] = []
  85. try:
  86. ext = cert.extensions.get_extension_for_oid(
  87. ExtensionOID.SUBJECT_ALTERNATIVE_NAME
  88. )
  89. except ExtensionNotFound:
  90. pass
  91. else:
  92. ids.extend(
  93. [
  94. DNSPattern.from_bytes(name.encode("utf-8"))
  95. for name in ext.value.get_values_for_type(DNSName)
  96. ]
  97. )
  98. ids.extend(
  99. [
  100. URIPattern.from_bytes(uri.encode("utf-8"))
  101. for uri in ext.value.get_values_for_type(
  102. UniformResourceIdentifier
  103. )
  104. ]
  105. )
  106. ids.extend(
  107. [
  108. IPAddressPattern(ip)
  109. for ip in ext.value.get_values_for_type(IPAddress)
  110. ]
  111. )
  112. for other in ext.value.get_values_for_type(OtherName):
  113. if other.type_id == ID_ON_DNS_SRV:
  114. srv, _ = decode(other.value)
  115. if isinstance(srv, IA5String):
  116. ids.append(SRVPattern.from_bytes(srv.asOctets()))
  117. else: # pragma: no cover
  118. raise CertificateError("Unexpected certificate content.")
  119. return ids
  120. def extract_ids(cert: Certificate) -> Sequence[CertificatePattern]:
  121. """
  122. Deprecated and never public API. Use :func:`extract_patterns` instead.
  123. .. deprecated:: 23.1.0
  124. """
  125. warnings.warn(
  126. category=DeprecationWarning,
  127. message="`extract_ids()` is deprecated, please use `extract_patterns()`.",
  128. stacklevel=2,
  129. )
  130. return extract_patterns(cert)