• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# SPDX-License-Identifier: GPL-2.0-only
2# This file is part of Scapy
3# See https://scapy.net/ for more information
4# Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
5#               2015, 2016, 2017 Maxence Tury
6
7"""
8TLS Pseudorandom Function.
9"""
10
11from scapy.error import warning
12from scapy.utils import strxor
13
14from scapy.layers.tls.crypto.hash import _tls_hash_algs
15from scapy.layers.tls.crypto.h_mac import _tls_hmac_algs
16from scapy.compat import bytes_encode
17
18
19# Data expansion functions
20
21def _tls_P_hash(secret, seed, req_len, hm):
22    """
23    Provides the implementation of P_hash function defined in
24    section 5 of RFC 4346 (and section 5 of RFC 5246). Two
25    parameters have been added (hm and req_len):
26
27    - secret : the key to be used. If RFC 4868 is to be believed,
28               the length must match hm.key_len. Actually,
29               python hmac takes care of formatting every key.
30    - seed : the seed to be used.
31    - req_len : the length of data to be generated by iterating
32               the specific HMAC function (hm). This prevents
33               multiple calls to the function.
34    - hm : the hmac function class to use for iteration (either
35           Hmac_MD5 or Hmac_SHA1 in TLS <= 1.1 or
36           Hmac_SHA256 or Hmac_SHA384 in TLS 1.2)
37    """
38    hash_len = hm.hash_alg.hash_len
39    n = (req_len + hash_len - 1) // hash_len
40    seed = bytes_encode(seed)
41
42    res = b""
43    a = hm(secret).digest(seed)  # A(1)
44
45    while n > 0:
46        res += hm(secret).digest(a + seed)
47        a = hm(secret).digest(a)
48        n -= 1
49
50    return res[:req_len]
51
52
53def _tls_P_MD5(secret, seed, req_len):
54    return _tls_P_hash(secret, seed, req_len, _tls_hmac_algs["HMAC-MD5"])
55
56
57def _tls_P_SHA1(secret, seed, req_len):
58    return _tls_P_hash(secret, seed, req_len, _tls_hmac_algs["HMAC-SHA"])
59
60
61def _tls_P_SHA256(secret, seed, req_len):
62    return _tls_P_hash(secret, seed, req_len, _tls_hmac_algs["HMAC-SHA256"])
63
64
65def _tls_P_SHA384(secret, seed, req_len):
66    return _tls_P_hash(secret, seed, req_len, _tls_hmac_algs["HMAC-SHA384"])
67
68
69def _tls_P_SHA512(secret, seed, req_len):
70    return _tls_P_hash(secret, seed, req_len, _tls_hmac_algs["HMAC-SHA512"])
71
72
73# PRF functions, according to the protocol version
74
75def _sslv2_PRF(secret, seed, req_len):
76    hash_md5 = _tls_hash_algs["MD5"]()
77    rounds = (req_len + hash_md5.hash_len - 1) // hash_md5.hash_len
78
79    res = b""
80    if rounds == 1:
81        res += hash_md5.digest(secret + seed)
82    else:
83        r = 0
84        while r < rounds:
85            label = str(r).encode("utf8")
86            res += hash_md5.digest(secret + label + seed)
87            r += 1
88
89    return res[:req_len]
90
91
92def _ssl_PRF(secret, seed, req_len):
93    """
94    Provides the implementation of SSLv3 PRF function:
95
96     SSLv3-PRF(secret, seed) =
97        MD5(secret || SHA-1("A" || secret || seed)) ||
98        MD5(secret || SHA-1("BB" || secret || seed)) ||
99        MD5(secret || SHA-1("CCC" || secret || seed)) || ...
100
101    req_len should not be more than  26 x 16 = 416.
102    """
103    if req_len > 416:
104        warning("_ssl_PRF() is not expected to provide more than 416 bytes")
105        return ""
106
107    d = [b"A", b"B", b"C", b"D", b"E", b"F", b"G", b"H", b"I", b"J", b"K", b"L",  # noqa: E501
108         b"M", b"N", b"O", b"P", b"Q", b"R", b"S", b"T", b"U", b"V", b"W", b"X",  # noqa: E501
109         b"Y", b"Z"]
110    res = b""
111    hash_sha1 = _tls_hash_algs["SHA"]()
112    hash_md5 = _tls_hash_algs["MD5"]()
113    rounds = (req_len + hash_md5.hash_len - 1) // hash_md5.hash_len
114
115    for i in range(rounds):
116        label = d[i] * (i + 1)
117        tmp = hash_sha1.digest(label + secret + seed)
118        res += hash_md5.digest(secret + tmp)
119
120    return res[:req_len]
121
122
123def _tls_PRF(secret, label, seed, req_len):
124    """
125    Provides the implementation of TLS PRF function as defined in
126    section 5 of RFC 4346:
127
128    PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR
129                               P_SHA-1(S2, label + seed)
130
131    Parameters are:
132
133    - secret: the secret used by the HMAC in the 2 expansion
134              functions (S1 and S2 are the halves of this secret).
135    - label: specific label as defined in various sections of the RFC
136             depending on the use of the generated PRF keystream
137    - seed: the seed used by the expansion functions.
138    - req_len: amount of keystream to be generated
139    """
140    tmp_len = (len(secret) + 1) // 2
141    S1 = secret[:tmp_len]
142    S2 = secret[-tmp_len:]
143
144    a1 = _tls_P_MD5(S1, label + seed, req_len)
145    a2 = _tls_P_SHA1(S2, label + seed, req_len)
146
147    return strxor(a1, a2)
148
149
150def _tls12_SHA256PRF(secret, label, seed, req_len):
151    """
152    Provides the implementation of TLS 1.2 PRF function as
153    defined in section 5 of RFC 5246:
154
155    PRF(secret, label, seed) = P_SHA256(secret, label + seed)
156
157    Parameters are:
158
159    - secret: the secret used by the HMAC in the 2 expansion
160              functions (S1 and S2 are the halves of this secret).
161    - label: specific label as defined in various sections of the RFC
162             depending on the use of the generated PRF keystream
163    - seed: the seed used by the expansion functions.
164    - req_len: amount of keystream to be generated
165    """
166    return _tls_P_SHA256(secret, label + seed, req_len)
167
168
169def _tls12_SHA384PRF(secret, label, seed, req_len):
170    return _tls_P_SHA384(secret, label + seed, req_len)
171
172
173def _tls12_SHA512PRF(secret, label, seed, req_len):
174    return _tls_P_SHA512(secret, label + seed, req_len)
175
176
177class PRF(object):
178    """
179    The PRF used by SSL/TLS varies based on the version of the protocol and
180    (for TLS 1.2) possibly the Hash algorithm of the negotiated cipher suite.
181    The various uses of the PRF (key derivation, computation of verify_data,
182    computation of pre_master_secret values) for the different versions of the
183    protocol also changes. In order to abstract those elements, the common
184    _tls_PRF() object is provided. It is expected to be initialised in the
185    context of the connection state using the tls_version and the cipher suite.
186    """
187
188    def __init__(self, hash_name="SHA256", tls_version=0x0303):
189        self.tls_version = tls_version
190        self.hash_name = hash_name
191
192        if tls_version < 0x0300:            # SSLv2
193            self.prf = _sslv2_PRF
194        elif tls_version == 0x0300:         # SSLv3
195            self.prf = _ssl_PRF
196        elif (tls_version == 0x0301 or      # TLS 1.0
197              tls_version == 0x0302):       # TLS 1.1
198            self.prf = _tls_PRF
199        elif tls_version == 0x0303:         # TLS 1.2
200            if hash_name == "SHA384":
201                self.prf = _tls12_SHA384PRF
202            elif hash_name == "SHA512":
203                self.prf = _tls12_SHA512PRF
204            else:
205                if hash_name in ["MD5", "SHA"]:
206                    self.hash_name = "SHA256"
207                self.prf = _tls12_SHA256PRF
208        else:
209            warning("Unknown TLS version")
210
211    def compute_master_secret(self, pre_master_secret, client_random,
212                              server_random, extms=False, handshake_hash=None):
213        """
214        Return the 48-byte master_secret, computed from pre_master_secret,
215        client_random and server_random. See RFC 5246, section 6.3.
216        Supports Extended Master Secret Derivation, see RFC 7627
217        """
218        seed = client_random + server_random
219        label = b'master secret'
220
221        if extms is True and handshake_hash is not None:
222            seed = handshake_hash
223            label = b'extended master secret'
224
225        if self.tls_version < 0x0300:
226            return None
227        elif self.tls_version == 0x0300:
228            return self.prf(pre_master_secret, seed, 48)
229        else:
230            return self.prf(pre_master_secret, label, seed, 48)
231
232    def derive_key_block(self, master_secret, server_random,
233                         client_random, req_len):
234        """
235        Perform the derivation of master_secret into a key_block of req_len
236        requested length. See RFC 5246, section 6.3.
237        """
238        seed = server_random + client_random
239        if self.tls_version <= 0x0300:
240            return self.prf(master_secret, seed, req_len)
241        else:
242            return self.prf(master_secret, b"key expansion", seed, req_len)
243
244    def compute_verify_data(self, con_end, read_or_write,
245                            handshake_msg, master_secret):
246        """
247        Return verify_data based on handshake messages, connection end,
248        master secret, and read_or_write position. See RFC 5246, section 7.4.9.
249
250        Every TLS 1.2 cipher suite has a verify_data of length 12. Note also::
251
252            "This PRF with the SHA-256 hash function is used for all cipher
253            suites defined in this document and in TLS documents published
254            prior to this document when TLS 1.2 is negotiated."
255
256        Cipher suites using SHA-384 were defined later on.
257        """
258        if self.tls_version < 0x0300:
259            return None
260        elif self.tls_version == 0x0300:
261
262            if read_or_write == "write":
263                d = {"client": b"CLNT", "server": b"SRVR"}
264            else:
265                d = {"client": b"SRVR", "server": b"CLNT"}
266            label = d[con_end]
267
268            sslv3_md5_pad1 = b"\x36" * 48
269            sslv3_md5_pad2 = b"\x5c" * 48
270            sslv3_sha1_pad1 = b"\x36" * 40
271            sslv3_sha1_pad2 = b"\x5c" * 40
272
273            md5 = _tls_hash_algs["MD5"]()
274            sha1 = _tls_hash_algs["SHA"]()
275
276            md5_hash = md5.digest(master_secret + sslv3_md5_pad2 +
277                                  md5.digest(handshake_msg + label +
278                                             master_secret + sslv3_md5_pad1))
279            sha1_hash = sha1.digest(master_secret + sslv3_sha1_pad2 +
280                                    sha1.digest(handshake_msg + label +
281                                                master_secret + sslv3_sha1_pad1))  # noqa: E501
282            verify_data = md5_hash + sha1_hash
283
284        else:
285
286            if read_or_write == "write":
287                d = {"client": "client", "server": "server"}
288            else:
289                d = {"client": "server", "server": "client"}
290            label = ("%s finished" % d[con_end]).encode()
291
292            if self.tls_version <= 0x0302:
293                s1 = _tls_hash_algs["MD5"]().digest(handshake_msg)
294                s2 = _tls_hash_algs["SHA"]().digest(handshake_msg)
295                verify_data = self.prf(master_secret, label, s1 + s2, 12)
296            else:
297                h = _tls_hash_algs[self.hash_name]()
298                s = h.digest(handshake_msg)
299                verify_data = self.prf(master_secret, label, s, 12)
300
301        return verify_data
302
303    def postprocess_key_for_export(self, key, client_random, server_random,
304                                   con_end, read_or_write, req_len):
305        """
306        Postprocess cipher key for EXPORT ciphersuite, i.e. weakens it.
307        An export key generation example is given in section 6.3.1 of RFC 2246.
308        See also page 86 of EKR's book.
309        """
310        s = con_end + read_or_write
311        s = (s == "clientwrite" or s == "serverread")
312
313        if self.tls_version < 0x0300:
314            return None
315        elif self.tls_version == 0x0300:
316            if s:
317                tbh = key + client_random + server_random
318            else:
319                tbh = key + server_random + client_random
320            export_key = _tls_hash_algs["MD5"]().digest(tbh)[:req_len]
321        else:
322            if s:
323                tag = b"client write key"
324            else:
325                tag = b"server write key"
326            export_key = self.prf(key,
327                                  tag,
328                                  client_random + server_random,
329                                  req_len)
330        return export_key
331
332    def generate_iv_for_export(self, client_random, server_random,
333                               con_end, read_or_write, req_len):
334        """
335        Generate IV for EXPORT ciphersuite, i.e. weakens it.
336        An export IV generation example is given in section 6.3.1 of RFC 2246.
337        See also page 86 of EKR's book.
338        """
339        s = con_end + read_or_write
340        s = (s == "clientwrite" or s == "serverread")
341
342        if self.tls_version < 0x0300:
343            return None
344        elif self.tls_version == 0x0300:
345            if s:
346                tbh = client_random + server_random
347            else:
348                tbh = server_random + client_random
349            iv = _tls_hash_algs["MD5"]().digest(tbh)[:req_len]
350        else:
351            iv_block = self.prf("",
352                                b"IV block",
353                                client_random + server_random,
354                                2 * req_len)
355            if s:
356                iv = iv_block[:req_len]
357            else:
358                iv = iv_block[req_len:]
359        return iv
360