1# Authors:
2#   Trevor Perrin
3#   Dave Baggett (Arcode Corporation) - Added TLSUnsupportedError.
4#
5# See the LICENSE file for legal information regarding use of this file.
6
7"""Exception classes.
8@sort: TLSError, TLSAbruptCloseError, TLSAlert, TLSLocalAlert, TLSRemoteAlert,
9TLSAuthenticationError, TLSNoAuthenticationError, TLSAuthenticationTypeError,
10TLSFingerprintError, TLSAuthorizationError, TLSValidationError, TLSFaultError,
11TLSUnsupportedError
12"""
13import socket
14
15from .constants import AlertDescription, AlertLevel
16
17class TLSError(Exception):
18    """Base class for all TLS Lite exceptions."""
19
20    def __str__(self):
21        """"At least print out the Exception time for str(...)."""
22        return repr(self)
23
24class TLSClosedConnectionError(TLSError, socket.error):
25    """An attempt was made to use the connection after it was closed."""
26    pass
27
28class TLSAbruptCloseError(TLSError):
29    """The socket was closed without a proper TLS shutdown.
30
31    The TLS specification mandates that an alert of some sort
32    must be sent before the underlying socket is closed.  If the socket
33    is closed without this, it could signify that an attacker is trying
34    to truncate the connection.  It could also signify a misbehaving
35    TLS implementation, or a random network failure.
36    """
37    pass
38
39class TLSAlert(TLSError):
40    """A TLS alert has been signalled."""
41    pass
42
43    _descriptionStr = {\
44        AlertDescription.close_notify: "close_notify",\
45        AlertDescription.unexpected_message: "unexpected_message",\
46        AlertDescription.bad_record_mac: "bad_record_mac",\
47        AlertDescription.decryption_failed: "decryption_failed",\
48        AlertDescription.record_overflow: "record_overflow",\
49        AlertDescription.decompression_failure: "decompression_failure",\
50        AlertDescription.handshake_failure: "handshake_failure",\
51        AlertDescription.no_certificate: "no certificate",\
52        AlertDescription.bad_certificate: "bad_certificate",\
53        AlertDescription.unsupported_certificate: "unsupported_certificate",\
54        AlertDescription.certificate_revoked: "certificate_revoked",\
55        AlertDescription.certificate_expired: "certificate_expired",\
56        AlertDescription.certificate_unknown: "certificate_unknown",\
57        AlertDescription.illegal_parameter: "illegal_parameter",\
58        AlertDescription.unknown_ca: "unknown_ca",\
59        AlertDescription.access_denied: "access_denied",\
60        AlertDescription.decode_error: "decode_error",\
61        AlertDescription.decrypt_error: "decrypt_error",\
62        AlertDescription.export_restriction: "export_restriction",\
63        AlertDescription.protocol_version: "protocol_version",\
64        AlertDescription.insufficient_security: "insufficient_security",\
65        AlertDescription.internal_error: "internal_error",\
66        AlertDescription.inappropriate_fallback: "inappropriate_fallback",\
67        AlertDescription.user_canceled: "user_canceled",\
68        AlertDescription.no_renegotiation: "no_renegotiation",\
69        AlertDescription.unknown_psk_identity: "unknown_psk_identity"}
70
71class TLSLocalAlert(TLSAlert):
72    """A TLS alert has been signalled by the local implementation.
73
74    @type description: int
75    @ivar description: Set to one of the constants in
76    L{tlslite.constants.AlertDescription}
77
78    @type level: int
79    @ivar level: Set to one of the constants in
80    L{tlslite.constants.AlertLevel}
81
82    @type message: str
83    @ivar message: Description of what went wrong.
84    """
85    def __init__(self, alert, message=None):
86        self.description = alert.description
87        self.level = alert.level
88        self.message = message
89
90    def __str__(self):
91        alertStr = TLSAlert._descriptionStr.get(self.description)
92        if alertStr == None:
93            alertStr = str(self.description)
94        if self.message:
95            return alertStr + ": " + self.message
96        else:
97            return alertStr
98
99class TLSRemoteAlert(TLSAlert):
100    """A TLS alert has been signalled by the remote implementation.
101
102    @type description: int
103    @ivar description: Set to one of the constants in
104    L{tlslite.constants.AlertDescription}
105
106    @type level: int
107    @ivar level: Set to one of the constants in
108    L{tlslite.constants.AlertLevel}
109    """
110    def __init__(self, alert):
111        self.description = alert.description
112        self.level = alert.level
113
114    def __str__(self):
115        alertStr = TLSAlert._descriptionStr.get(self.description)
116        if alertStr == None:
117            alertStr = str(self.description)
118        return alertStr
119
120class TLSAuthenticationError(TLSError):
121    """The handshake succeeded, but the other party's authentication
122    was inadequate.
123
124    This exception will only be raised when a
125    L{tlslite.Checker.Checker} has been passed to a handshake function.
126    The Checker will be invoked once the handshake completes, and if
127    the Checker objects to how the other party authenticated, a
128    subclass of this exception will be raised.
129    """
130    pass
131
132class TLSNoAuthenticationError(TLSAuthenticationError):
133    """The Checker was expecting the other party to authenticate with a
134    certificate chain, but this did not occur."""
135    pass
136
137class TLSAuthenticationTypeError(TLSAuthenticationError):
138    """The Checker was expecting the other party to authenticate with a
139    different type of certificate chain."""
140    pass
141
142class TLSFingerprintError(TLSAuthenticationError):
143    """The Checker was expecting the other party to authenticate with a
144    certificate chain that matches a different fingerprint."""
145    pass
146
147class TLSAuthorizationError(TLSAuthenticationError):
148    """The Checker was expecting the other party to authenticate with a
149    certificate chain that has a different authorization."""
150    pass
151
152class TLSValidationError(TLSAuthenticationError):
153    """The Checker has determined that the other party's certificate
154    chain is invalid."""
155    def __init__(self, msg, info=None):
156        # Include a dict containing info about this validation failure
157        TLSAuthenticationError.__init__(self, msg)
158        self.info = info
159
160class TLSFaultError(TLSError):
161    """The other party responded incorrectly to an induced fault.
162
163    This exception will only occur during fault testing, when a
164    TLSConnection's fault variable is set to induce some sort of
165    faulty behavior, and the other party doesn't respond appropriately.
166    """
167    pass
168
169
170class TLSUnsupportedError(TLSError):
171    """The implementation doesn't support the requested (or required)
172    capabilities."""
173    pass
174