/vendor/github.com/google/certificate-transparency/python/ct/cert_analysis/dnsnames.py

https://gitlab.com/unofficial-mirrors/openshift-origin · Python · 125 lines · 84 code · 22 blank · 19 comment · 15 complexity · 0c7c09a424a19640d330238cf11999cb MD5 · raw file

  1. from ct.crypto import cert
  2. import re
  3. from ct.cert_analysis.observation import Observation
  4. from ct.cert_analysis import tld_check
  5. class DNSNamesObservation(Observation):
  6. def __init__(self, description, *args, **kwargs):
  7. super(DNSNamesObservation, self).__init__("dNSNames: " + description,
  8. *args, **kwargs)
  9. class InvalidCharacter(DNSNamesObservation):
  10. def __init__(self, *args, **kwargs):
  11. super(InvalidCharacter, self).__init__("invalid character in name",
  12. *args, **kwargs)
  13. class CorruptSANExtension(DNSNamesObservation):
  14. def __init__(self):
  15. super(CorruptSANExtension, self).__init__("corrupt extension")
  16. class TldMatchesBothUnicodeAndIdna(DNSNamesObservation):
  17. def __init__(self, *args, **kwargs):
  18. super(DNSNamesObservation, self).__init__("unicode and idna encoding"
  19. "of address matches different top level domain names", *args,
  20. **kwargs)
  21. class NoTldMatch(DNSNamesObservation):
  22. def __init__(self, *args, **kwargs):
  23. super(NoTldMatch, self).__init__("no top level domain matches", *args,
  24. **kwargs)
  25. class NonUnicodeAddress(DNSNamesObservation):
  26. def __init__(self, *args, **kwargs):
  27. super(NonUnicodeAddress, self).__init__("non unicode address", *args,
  28. **kwargs)
  29. class NotAnAddress(DNSNamesObservation):
  30. def __init__(self, *args, **kwargs):
  31. super(NotAnAddress, self).__init__("not an address", *args,
  32. **kwargs)
  33. class GenericWildcard(DNSNamesObservation):
  34. def __init__(self, *args, **kwargs):
  35. super(GenericWildcard, self).__init__(
  36. "name wildcard matches top level domain name", *args,
  37. **kwargs)
  38. class CheckValidityOfDnsnames(object):
  39. # if this regex matches in any way, it can't be dnsname
  40. NOT_DNSNAME_REGEX = re.compile('[^a-zA-Z0-9\-.*]')
  41. @staticmethod
  42. def check(certificate):
  43. """Checks whether dNSNames contains correct characters.
  44. Returns:
  45. array containing InvalidCharacter or empty array
  46. """
  47. observations = []
  48. try:
  49. for name in certificate.subject_dns_names():
  50. # if there are funny characters from other encodings they will
  51. # cause either unicode to fail, or they will stay in idna
  52. # encoding and caught by regex
  53. try:
  54. utf_name = unicode(name.value, 'utf-8')
  55. except UnicodeError:
  56. observations.append(
  57. InvalidCharacter('failed to encode in utf-8',
  58. name.value))
  59. continue
  60. try:
  61. idna_name = utf_name.encode('idna')
  62. for match in CheckValidityOfDnsnames.NOT_DNSNAME_REGEX.findall(
  63. idna_name):
  64. reason = None
  65. if match == '@':
  66. reason = 'suspected email address'
  67. obs = InvalidCharacter(reason,
  68. (name.value, idna_name, match))
  69. observations += [obs]
  70. except UnicodeError:
  71. observations.append(
  72. InvalidCharacter('failed to encode in idna',
  73. utf_name))
  74. except cert.CertificateError:
  75. pass
  76. return observations
  77. class CheckTldMatches(object):
  78. """Checks whether dNSNames matches some top level domain name.
  79. Returns:
  80. array containing TldMatchesBothUnicodeAndIdna, NoTldMatch,
  81. GenericWildcard or None"""
  82. @classmethod
  83. def check(cls, certificate):
  84. try:
  85. return tld_check.CheckTldMatches.check(
  86. certificate.subject_dns_names(),
  87. "dNSNames: ")
  88. except cert.CertificateError:
  89. pass
  90. class CheckCorruptSANExtension(object):
  91. """Checks whether SAN extension is corrupt.
  92. Returns:
  93. array containing CorruptSANExtension or None
  94. """
  95. @staticmethod
  96. def check(certificate):
  97. try:
  98. certificate.subject_dns_names()
  99. except cert.CertificateError:
  100. return [CorruptSANExtension()]