/gdata/tlslite/Checker.py

http://radioappz.googlecode.com/ · Python · 146 lines · 112 code · 10 blank · 24 comment · 3 complexity · b387eac9221fd2c33dbf0629016f20d6 MD5 · raw file

  1. """Class for post-handshake certificate checking."""
  2. from utils.cryptomath import hashAndBase64
  3. from X509 import X509
  4. from X509CertChain import X509CertChain
  5. from errors import *
  6. class Checker:
  7. """This class is passed to a handshake function to check the other
  8. party's certificate chain.
  9. If a handshake function completes successfully, but the Checker
  10. judges the other party's certificate chain to be missing or
  11. inadequate, a subclass of
  12. L{tlslite.errors.TLSAuthenticationError} will be raised.
  13. Currently, the Checker can check either an X.509 or a cryptoID
  14. chain (for the latter, cryptoIDlib must be installed).
  15. """
  16. def __init__(self, cryptoID=None, protocol=None,
  17. x509Fingerprint=None,
  18. x509TrustList=None, x509CommonName=None,
  19. checkResumedSession=False):
  20. """Create a new Checker instance.
  21. You must pass in one of these argument combinations:
  22. - cryptoID[, protocol] (requires cryptoIDlib)
  23. - x509Fingerprint
  24. - x509TrustList[, x509CommonName] (requires cryptlib_py)
  25. @type cryptoID: str
  26. @param cryptoID: A cryptoID which the other party's certificate
  27. chain must match. The cryptoIDlib module must be installed.
  28. Mutually exclusive with all of the 'x509...' arguments.
  29. @type protocol: str
  30. @param protocol: A cryptoID protocol URI which the other
  31. party's certificate chain must match. Requires the 'cryptoID'
  32. argument.
  33. @type x509Fingerprint: str
  34. @param x509Fingerprint: A hex-encoded X.509 end-entity
  35. fingerprint which the other party's end-entity certificate must
  36. match. Mutually exclusive with the 'cryptoID' and
  37. 'x509TrustList' arguments.
  38. @type x509TrustList: list of L{tlslite.X509.X509}
  39. @param x509TrustList: A list of trusted root certificates. The
  40. other party must present a certificate chain which extends to
  41. one of these root certificates. The cryptlib_py module must be
  42. installed. Mutually exclusive with the 'cryptoID' and
  43. 'x509Fingerprint' arguments.
  44. @type x509CommonName: str
  45. @param x509CommonName: The end-entity certificate's 'CN' field
  46. must match this value. For a web server, this is typically a
  47. server name such as 'www.amazon.com'. Mutually exclusive with
  48. the 'cryptoID' and 'x509Fingerprint' arguments. Requires the
  49. 'x509TrustList' argument.
  50. @type checkResumedSession: bool
  51. @param checkResumedSession: If resumed sessions should be
  52. checked. This defaults to False, on the theory that if the
  53. session was checked once, we don't need to bother
  54. re-checking it.
  55. """
  56. if cryptoID and (x509Fingerprint or x509TrustList):
  57. raise ValueError()
  58. if x509Fingerprint and x509TrustList:
  59. raise ValueError()
  60. if x509CommonName and not x509TrustList:
  61. raise ValueError()
  62. if protocol and not cryptoID:
  63. raise ValueError()
  64. if cryptoID:
  65. import cryptoIDlib #So we raise an error here
  66. if x509TrustList:
  67. import cryptlib_py #So we raise an error here
  68. self.cryptoID = cryptoID
  69. self.protocol = protocol
  70. self.x509Fingerprint = x509Fingerprint
  71. self.x509TrustList = x509TrustList
  72. self.x509CommonName = x509CommonName
  73. self.checkResumedSession = checkResumedSession
  74. def __call__(self, connection):
  75. """Check a TLSConnection.
  76. When a Checker is passed to a handshake function, this will
  77. be called at the end of the function.
  78. @type connection: L{tlslite.TLSConnection.TLSConnection}
  79. @param connection: The TLSConnection to examine.
  80. @raise tlslite.errors.TLSAuthenticationError: If the other
  81. party's certificate chain is missing or bad.
  82. """
  83. if not self.checkResumedSession and connection.resumed:
  84. return
  85. if self.cryptoID or self.x509Fingerprint or self.x509TrustList:
  86. if connection._client:
  87. chain = connection.session.serverCertChain
  88. else:
  89. chain = connection.session.clientCertChain
  90. if self.x509Fingerprint or self.x509TrustList:
  91. if isinstance(chain, X509CertChain):
  92. if self.x509Fingerprint:
  93. if chain.getFingerprint() != self.x509Fingerprint:
  94. raise TLSFingerprintError(\
  95. "X.509 fingerprint mismatch: %s, %s" % \
  96. (chain.getFingerprint(), self.x509Fingerprint))
  97. else: #self.x509TrustList
  98. if not chain.validate(self.x509TrustList):
  99. raise TLSValidationError("X.509 validation failure")
  100. if self.x509CommonName and \
  101. (chain.getCommonName() != self.x509CommonName):
  102. raise TLSAuthorizationError(\
  103. "X.509 Common Name mismatch: %s, %s" % \
  104. (chain.getCommonName(), self.x509CommonName))
  105. elif chain:
  106. raise TLSAuthenticationTypeError()
  107. else:
  108. raise TLSNoAuthenticationError()
  109. elif self.cryptoID:
  110. import cryptoIDlib.CertChain
  111. if isinstance(chain, cryptoIDlib.CertChain.CertChain):
  112. if chain.cryptoID != self.cryptoID:
  113. raise TLSFingerprintError(\
  114. "cryptoID mismatch: %s, %s" % \
  115. (chain.cryptoID, self.cryptoID))
  116. if self.protocol:
  117. if not chain.checkProtocol(self.protocol):
  118. raise TLSAuthorizationError(\
  119. "cryptoID protocol mismatch")
  120. if not chain.validate():
  121. raise TLSValidationError("cryptoID validation failure")
  122. elif chain:
  123. raise TLSAuthenticationTypeError()
  124. else:
  125. raise TLSNoAuthenticationError()