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