1# Authors:
2#   Trevor Perrin
3#   Dave Baggett (Arcode Corporation) - cleanup handling of constants
4#
5# See the LICENSE file for legal information regarding use of this file.
6
7"""Class for setting handshake parameters."""
8
9from .constants import CertificateType
10from .utils import cryptomath
11from .utils import cipherfactory
12
13# RC4 is preferred as faster in Python, works in SSL3, and immune to CBC
14# issues such as timing attacks
15CIPHER_NAMES = ["rc4", "aes256", "aes128", "3des"]
16MAC_NAMES = ["sha"] # Don't allow "md5" by default.
17ALL_MAC_NAMES = ["sha", "md5"]
18KEY_EXCHANGE_NAMES = ["rsa", "dhe_rsa", "srp_sha", "srp_sha_rsa", "dh_anon"]
19CIPHER_IMPLEMENTATIONS = ["openssl", "pycrypto", "python"]
20CERTIFICATE_TYPES = ["x509"]
21TLS_INTOLERANCE_TYPES = ["alert", "close", "reset"]
22
23class HandshakeSettings(object):
24    """This class encapsulates various parameters that can be used with
25    a TLS handshake.
26    @sort: minKeySize, maxKeySize, cipherNames, macNames, certificateTypes,
27    minVersion, maxVersion
28
29    @type minKeySize: int
30    @ivar minKeySize: The minimum bit length for asymmetric keys.
31
32    If the other party tries to use SRP, RSA, or Diffie-Hellman
33    parameters smaller than this length, an alert will be
34    signalled.  The default is 1023.
35
36    @type maxKeySize: int
37    @ivar maxKeySize: The maximum bit length for asymmetric keys.
38
39    If the other party tries to use SRP, RSA, or Diffie-Hellman
40    parameters larger than this length, an alert will be signalled.
41    The default is 8193.
42
43    @type cipherNames: list
44    @ivar cipherNames: The allowed ciphers, in order of preference.
45
46    The allowed values in this list are 'aes256', 'aes128', '3des', and
47    'rc4'.  If these settings are used with a client handshake, they
48    determine the order of the ciphersuites offered in the ClientHello
49    message.
50
51    If these settings are used with a server handshake, the server will
52    choose whichever ciphersuite matches the earliest entry in this
53    list.
54
55    NOTE:  If '3des' is used in this list, but TLS Lite can't find an
56    add-on library that supports 3DES, then '3des' will be silently
57    removed.
58
59    The default value is ['rc4', 'aes256', 'aes128', '3des'].
60
61    @type macNames: list
62    @ivar macNames: The allowed MAC algorithms.
63
64    The allowed values in this list are 'sha' and 'md5'.
65
66    The default value is ['sha'].
67
68
69    @type certificateTypes: list
70    @ivar certificateTypes: The allowed certificate types, in order of
71    preference.
72
73    The only allowed certificate type is 'x509'.  This list is only used with a
74    client handshake.  The client will advertise to the server which certificate
75    types are supported, and will check that the server uses one of the
76    appropriate types.
77
78
79    @type minVersion: tuple
80    @ivar minVersion: The minimum allowed SSL/TLS version.
81
82    This variable can be set to (3,0) for SSL 3.0, (3,1) for
83    TLS 1.0, or (3,2) for TLS 1.1.  If the other party wishes to
84    use a lower version, a protocol_version alert will be signalled.
85    The default is (3,0).
86
87    @type maxVersion: tuple
88    @ivar maxVersion: The maximum allowed SSL/TLS version.
89
90    This variable can be set to (3,0) for SSL 3.0, (3,1) for
91    TLS 1.0, or (3,2) for TLS 1.1.  If the other party wishes to
92    use a higher version, a protocol_version alert will be signalled.
93    The default is (3,2).  (WARNING: Some servers may (improperly)
94    reject clients which offer support for TLS 1.1.  In this case,
95    try lowering maxVersion to (3,1)).
96
97    @type tlsIntolerant: tuple
98    @ivar tlsIntolerant: The TLS ClientHello version which the server
99    simulates intolerance of.
100
101    If tlsIntolerant is not None, the server will simulate TLS version
102    intolerance by aborting the handshake in response to all TLS versions
103    tlsIntolerant or higher.
104
105    @type tlsIntoleranceType: str
106    @ivar tlsIntoleranceType: How the server should react when simulating TLS
107    intolerance.
108
109    The allowed values are "alert" (return a fatal handshake_failure alert),
110    "close" (abruptly close the connection), and "reset" (send a TCP reset).
111
112    @type useExperimentalTackExtension: bool
113    @ivar useExperimentalTackExtension: Whether to enabled TACK support.
114
115    Note that TACK support is not standardized by IETF and uses a temporary
116    TLS Extension number, so should NOT be used in production software.
117    """
118    def __init__(self):
119        self.minKeySize = 1023
120        self.maxKeySize = 8193
121        self.cipherNames = CIPHER_NAMES
122        self.macNames = MAC_NAMES
123        self.keyExchangeNames = KEY_EXCHANGE_NAMES
124        self.cipherImplementations = CIPHER_IMPLEMENTATIONS
125        self.certificateTypes = CERTIFICATE_TYPES
126        self.minVersion = (3,0)
127        self.maxVersion = (3,2)
128        self.tlsIntolerant = None
129        self.tlsIntoleranceType = 'alert'
130        self.useExperimentalTackExtension = False
131
132    # Validates the min/max fields, and certificateTypes
133    # Filters out unsupported cipherNames and cipherImplementations
134    def _filter(self):
135        other = HandshakeSettings()
136        other.minKeySize = self.minKeySize
137        other.maxKeySize = self.maxKeySize
138        other.cipherNames = self.cipherNames
139        other.macNames = self.macNames
140        other.keyExchangeNames = self.keyExchangeNames
141        other.cipherImplementations = self.cipherImplementations
142        other.certificateTypes = self.certificateTypes
143        other.minVersion = self.minVersion
144        other.maxVersion = self.maxVersion
145        other.tlsIntolerant = self.tlsIntolerant
146        other.tlsIntoleranceType = self.tlsIntoleranceType
147
148        if not cipherfactory.tripleDESPresent:
149            other.cipherNames = [e for e in self.cipherNames if e != "3des"]
150        if len(other.cipherNames)==0:
151            raise ValueError("No supported ciphers")
152        if len(other.certificateTypes)==0:
153            raise ValueError("No supported certificate types")
154
155        if not cryptomath.m2cryptoLoaded:
156            other.cipherImplementations = \
157                [e for e in other.cipherImplementations if e != "openssl"]
158        if not cryptomath.pycryptoLoaded:
159            other.cipherImplementations = \
160                [e for e in other.cipherImplementations if e != "pycrypto"]
161        if len(other.cipherImplementations)==0:
162            raise ValueError("No supported cipher implementations")
163
164        if other.minKeySize<512:
165            raise ValueError("minKeySize too small")
166        if other.minKeySize>16384:
167            raise ValueError("minKeySize too large")
168        if other.maxKeySize<512:
169            raise ValueError("maxKeySize too small")
170        if other.maxKeySize>16384:
171            raise ValueError("maxKeySize too large")
172        for s in other.cipherNames:
173            if s not in CIPHER_NAMES:
174                raise ValueError("Unknown cipher name: '%s'" % s)
175        for s in other.macNames:
176            if s not in ALL_MAC_NAMES:
177                raise ValueError("Unknown MAC name: '%s'" % s)
178        for s in other.keyExchangeNames:
179            if s not in KEY_EXCHANGE_NAMES:
180                raise ValueError("Unknown key exchange name: '%s'" % s)
181        for s in other.cipherImplementations:
182            if s not in CIPHER_IMPLEMENTATIONS:
183                raise ValueError("Unknown cipher implementation: '%s'" % s)
184        for s in other.certificateTypes:
185            if s not in CERTIFICATE_TYPES:
186                raise ValueError("Unknown certificate type: '%s'" % s)
187
188        if other.tlsIntoleranceType not in TLS_INTOLERANCE_TYPES:
189            raise ValueError(
190                "Unknown TLS intolerance type: '%s'" % other.tlsIntoleranceType)
191
192        if other.minVersion > other.maxVersion:
193            raise ValueError("Versions set incorrectly")
194
195        if not other.minVersion in ((3,0), (3,1), (3,2)):
196            raise ValueError("minVersion set incorrectly")
197
198        if not other.maxVersion in ((3,0), (3,1), (3,2)):
199            raise ValueError("maxVersion set incorrectly")
200
201        return other
202
203    def _getCertificateTypes(self):
204        l = []
205        for ct in self.certificateTypes:
206            if ct == "x509":
207                l.append(CertificateType.x509)
208            else:
209                raise AssertionError()
210        return l
211