• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1## This file is part of Scapy
2## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
3##               2015, 2016, 2017 Maxence Tury
4## This program is published under a GPLv2 license
5
6"""
7TLS key exchange logic.
8"""
9
10from __future__ import absolute_import
11import math
12
13from scapy.config import conf, crypto_validator
14from scapy.error import warning
15from scapy.fields import *
16from scapy.compat import orb
17from scapy.packet import Packet, Raw, Padding
18from scapy.layers.tls.cert import PubKeyRSA, PrivKeyRSA
19from scapy.layers.tls.session import _GenericTLSSessionInheritance
20from scapy.layers.tls.basefields import _tls_version, _TLSClientVersionField
21from scapy.layers.tls.crypto.pkcs1 import pkcs_i2osp, pkcs_os2ip
22from scapy.layers.tls.crypto.groups import _ffdh_groups, _tls_named_curves
23import scapy.modules.six as six
24
25if conf.crypto_valid:
26    from cryptography.hazmat.backends import default_backend
27    from cryptography.hazmat.primitives.asymmetric import dh, ec
28
29
30###############################################################################
31### Common Fields                                                           ###
32###############################################################################
33
34_tls_hash_sig = { 0x0000: "none+anon",    0x0001: "none+rsa",
35                  0x0002: "none+dsa",     0x0003: "none+ecdsa",
36                  0x0100: "md5+anon",     0x0101: "md5+rsa",
37                  0x0102: "md5+dsa",      0x0103: "md5+ecdsa",
38                  0x0200: "sha1+anon",    0x0201: "sha1+rsa",
39                  0x0202: "sha1+dsa",     0x0203: "sha1+ecdsa",
40                  0x0300: "sha224+anon",  0x0301: "sha224+rsa",
41                  0x0302: "sha224+dsa",   0x0303: "sha224+ecdsa",
42                  0x0400: "sha256+anon",  0x0401: "sha256+rsa",
43                  0x0402: "sha256+dsa",   0x0403: "sha256+ecdsa",
44                  0x0500: "sha384+anon",  0x0501: "sha384+rsa",
45                  0x0502: "sha384+dsa",   0x0503: "sha384+ecdsa",
46                  0x0600: "sha512+anon",  0x0601: "sha512+rsa",
47                  0x0602: "sha512+dsa",   0x0603: "sha512+ecdsa",
48                  0x0804: "sha256+rsapss",
49                  0x0805: "sha384+rsapss",
50                  0x0806: "sha512+rsapss",
51                  0x0807: "ed25519",
52                  0x0808: "ed448" }
53
54
55def phantom_mode(pkt):
56    """
57    We expect this. If tls_version is not set, this means we did not process
58    any complete ClientHello, so we're most probably reading/building a
59    signature_algorithms extension, hence we cannot be in phantom_mode.
60    However, if the tls_version has been set, we test for TLS 1.2.
61    """
62    if not pkt.tls_session:
63        return False
64    if not pkt.tls_session.tls_version:
65        return False
66    return pkt.tls_session.tls_version < 0x0303
67
68def phantom_decorate(f, get_or_add):
69    """
70    Decorator for version-dependent fields.
71    If get_or_add is True (means get), we return s, self.phantom_value.
72    If it is False (means add), we return s.
73    """
74    def wrapper(*args):
75        self, pkt, s = args[:3]
76        if phantom_mode(pkt):
77            if get_or_add:
78                return s, self.phantom_value
79            return s
80        return f(*args)
81    return wrapper
82
83class SigAndHashAlgField(EnumField):
84    """Used in _TLSSignature."""
85    phantom_value = None
86    getfield = phantom_decorate(EnumField.getfield, True)
87    addfield = phantom_decorate(EnumField.addfield, False)
88
89class SigAndHashAlgsLenField(FieldLenField):
90    """Used in TLS_Ext_SignatureAlgorithms and TLSCertificateResquest."""
91    phantom_value = 0
92    getfield = phantom_decorate(FieldLenField.getfield, True)
93    addfield = phantom_decorate(FieldLenField.addfield, False)
94
95class SigAndHashAlgsField(FieldListField):
96    """Used in TLS_Ext_SignatureAlgorithms and TLSCertificateResquest."""
97    phantom_value = []
98    getfield = phantom_decorate(FieldListField.getfield, True)
99    addfield = phantom_decorate(FieldListField.addfield, False)
100
101
102class SigLenField(FieldLenField):
103    """There is a trick for SSLv2, which uses implicit lengths..."""
104    def getfield(self, pkt, s):
105        v = pkt.tls_session.tls_version
106        if v and v < 0x0300:
107            return s, None
108        return super(SigLenField, self).getfield(pkt, s)
109
110    def addfield(self, pkt, s, val):
111        """With SSLv2 you will never be able to add a sig_len."""
112        v = pkt.tls_session.tls_version
113        if v and v < 0x0300:
114            return s
115        return super(SigLenField, self).addfield(pkt, s, val)
116
117class SigValField(StrLenField):
118    """There is a trick for SSLv2, which uses implicit lengths..."""
119    def getfield(self, pkt, m):
120        s = pkt.tls_session
121        if s.tls_version and s.tls_version < 0x0300:
122            if len(s.client_certs) > 0:
123                sig_len = s.client_certs[0].pubKey.pubkey.key_size // 8
124            else:
125                warning("No client certificate provided. "
126                        "We're making a wild guess about the signature size.")
127                sig_len = 256
128            return m[sig_len:], self.m2i(pkt, m[:sig_len])
129        return super(SigValField, self).getfield(pkt, m)
130
131
132class _TLSSignature(_GenericTLSSessionInheritance):
133    """
134    Prior to TLS 1.2, digitally-signed structure implicitly used the
135    concatenation of a MD5 hash and a SHA-1 hash.
136    Then TLS 1.2 introduced explicit SignatureAndHashAlgorithms,
137    i.e. couples of (hash_alg, sig_alg). See RFC 5246, section 7.4.1.4.1.
138
139    By default, the _TLSSignature implements the TLS 1.2 scheme,
140    but if it is provided a TLS context with a tls_version < 0x0303
141    at initialization, it will fall back to the implicit signature.
142    Even more, the 'sig_len' field won't be used with SSLv2.
143
144    #XXX 'sig_alg' should be set in __init__ depending on the context.
145    """
146    name = "TLS Digital Signature"
147    fields_desc = [ SigAndHashAlgField("sig_alg", 0x0401, _tls_hash_sig),
148                    SigLenField("sig_len", None, fmt="!H",
149                                length_of="sig_val"),
150                    SigValField("sig_val", None,
151                                length_from=lambda pkt: pkt.sig_len) ]
152
153    def __init__(self, *args, **kargs):
154        super(_TLSSignature, self).__init__(*args, **kargs)
155        if (self.tls_session and
156            self.tls_session.tls_version and
157            self.tls_session.tls_version < 0x0303):
158            self.sig_alg = None
159
160    def _update_sig(self, m, key):
161        """
162        Sign 'm' with the PrivKey 'key' and update our own 'sig_val'.
163        Note that, even when 'sig_alg' is not None, we use the signature scheme
164        of the PrivKey (neither do we care to compare the both of them).
165        """
166        if self.sig_alg is None:
167            if self.tls_session.tls_version >= 0x0300:
168                self.sig_val = key.sign(m, t='pkcs', h='md5-sha1')
169            else:
170                self.sig_val = key.sign(m, t='pkcs', h='md5')
171        else:
172            h, sig = _tls_hash_sig[self.sig_alg].split('+')
173            if sig.endswith('pss'):
174                t = "pss"
175            else:
176                t = "pkcs"
177            self.sig_val = key.sign(m, t=t, h=h)
178
179    def _verify_sig(self, m, cert):
180        """
181        Verify that our own 'sig_val' carries the signature of 'm' by the
182        key associated to the Cert 'cert'.
183        """
184        if self.sig_val:
185            if self.sig_alg:
186                h, sig = _tls_hash_sig[self.sig_alg].split('+')
187                if sig.endswith('pss'):
188                    t = "pss"
189                else:
190                    t = "pkcs"
191                return cert.verify(m, self.sig_val, t=t, h=h)
192            else:
193                if self.tls_session.tls_version >= 0x0300:
194                    return cert.verify(m, self.sig_val, t='pkcs', h='md5-sha1')
195                else:
196                    return cert.verify(m, self.sig_val, t='pkcs', h='md5')
197        return False
198
199    def guess_payload_class(self, p):
200        return Padding
201
202class _TLSSignatureField(PacketField):
203    """
204    Used for 'digitally-signed struct' in several ServerKeyExchange,
205    and also in CertificateVerify. We can handle the anonymous case.
206    """
207    __slots__ = ["length_from"]
208    def __init__(self, name, default, length_from=None, remain=0):
209        self.length_from = length_from
210        PacketField.__init__(self, name, default, _TLSSignature, remain=remain)
211
212    def m2i(self, pkt, m):
213        l = self.length_from(pkt)
214        if l == 0:
215           return None
216        return _TLSSignature(m, tls_session=pkt.tls_session)
217
218    def getfield(self, pkt, s):
219        i = self.m2i(pkt, s)
220        if i is None:
221            return s, None
222        remain = b""
223        if conf.padding_layer in i:
224            r = i[conf.padding_layer]
225            del(r.underlayer.payload)
226            remain = r.load
227        return remain, i
228
229
230class _TLSServerParamsField(PacketField):
231    """
232    This is a dispatcher for the Server*DHParams below, used in
233    TLSServerKeyExchange and based on the key_exchange.server_kx_msg_cls.
234    When this cls is None, it means that we should not see a ServerKeyExchange,
235    so we grab everything within length_from and make it available using Raw.
236
237    When the context has not been set (e.g. when no ServerHello was parsed or
238    dissected beforehand), we (kinda) clumsily set the cls by trial and error.
239    XXX We could use Serv*DHParams.check_params() once it has been implemented.
240    """
241    __slots__ = ["length_from"]
242    def __init__(self, name, default, length_from=None, remain=0):
243        self.length_from = length_from
244        PacketField.__init__(self, name, default, None, remain=remain)
245
246    def m2i(self, pkt, m):
247        s = pkt.tls_session
248        l = self.length_from(pkt)
249        if s.prcs:
250            cls = s.prcs.key_exchange.server_kx_msg_cls(m)
251            if cls is None:
252                return None, Raw(m[:l])/Padding(m[l:])
253            return cls(m, tls_session=s)
254        else:
255            try:
256                p = ServerDHParams(m, tls_session=s)
257                if pkcs_os2ip(p.load[:2]) not in _tls_hash_sig:
258                    raise Exception
259                return p
260            except:
261                cls = _tls_server_ecdh_cls_guess(m)
262                p = cls(m, tls_session=s)
263                if pkcs_os2ip(p.load[:2]) not in _tls_hash_sig:
264                    return None, Raw(m[:l])/Padding(m[l:])
265                return p
266
267
268###############################################################################
269### Server Key Exchange parameters & value                                  ###
270###############################################################################
271
272### Finite Field Diffie-Hellman
273
274class ServerDHParams(_GenericTLSSessionInheritance):
275    """
276    ServerDHParams for FFDH-based key exchanges, as defined in RFC 5246/7.4.3.
277
278    Either with .fill_missing() or .post_dissection(), the server_kx_privkey or
279    server_kx_pubkey of the TLS context are updated according to the
280    parsed/assembled values. It is the user's responsibility to store and
281    restore the original values if he wants to keep them. For instance, this
282    could be done between the writing of a ServerKeyExchange and the receiving
283    of a ClientKeyExchange (which includes secret generation).
284    """
285    name = "Server FFDH parameters"
286    fields_desc = [ FieldLenField("dh_plen", None, length_of="dh_p"),
287                    StrLenField("dh_p", "",
288                                length_from=lambda pkt: pkt.dh_plen),
289                    FieldLenField("dh_glen", None, length_of="dh_g"),
290                    StrLenField("dh_g", "",
291                                length_from=lambda pkt: pkt.dh_glen),
292                    FieldLenField("dh_Yslen", None, length_of="dh_Ys"),
293                    StrLenField("dh_Ys", "",
294                                length_from=lambda pkt: pkt.dh_Yslen) ]
295
296    @crypto_validator
297    def fill_missing(self):
298        """
299        We do not want TLSServerKeyExchange.build() to overload and recompute
300        things everytime it is called. This method can be called specifically
301        to have things filled in a smart fashion.
302
303        Note that we do not expect default_params.g to be more than 0xff.
304        """
305        s = self.tls_session
306
307        default_params = _ffdh_groups['modp2048'][0].parameter_numbers()
308        default_mLen = _ffdh_groups['modp2048'][1]
309
310        if not self.dh_p:
311            self.dh_p = pkcs_i2osp(default_params.p, default_mLen//8)
312        if self.dh_plen is None:
313            self.dh_plen = len(self.dh_p)
314
315        if not self.dh_g:
316            self.dh_g = pkcs_i2osp(default_params.g, 1)
317        if self.dh_glen is None:
318            self.dh_glen = 1
319
320        p = pkcs_os2ip(self.dh_p)
321        g = pkcs_os2ip(self.dh_g)
322        real_params = dh.DHParameterNumbers(p, g).parameters(default_backend())
323
324        if not self.dh_Ys:
325            s.server_kx_privkey = real_params.generate_private_key()
326            pubkey = s.server_kx_privkey.public_key()
327            y = pubkey.public_numbers().y
328            self.dh_Ys = pkcs_i2osp(y, pubkey.key_size//8)
329        # else, we assume that the user wrote the server_kx_privkey by himself
330        if self.dh_Yslen is None:
331            self.dh_Yslen = len(self.dh_Ys)
332
333        if not s.client_kx_ffdh_params:
334            s.client_kx_ffdh_params = real_params
335
336    @crypto_validator
337    def register_pubkey(self):
338        """
339        XXX Check that the pubkey received is in the group.
340        """
341        p = pkcs_os2ip(self.dh_p)
342        g = pkcs_os2ip(self.dh_g)
343        pn = dh.DHParameterNumbers(p, g)
344
345        y = pkcs_os2ip(self.dh_Ys)
346        public_numbers = dh.DHPublicNumbers(y, pn)
347
348        s = self.tls_session
349        s.server_kx_pubkey = public_numbers.public_key(default_backend())
350
351        if not s.client_kx_ffdh_params:
352            s.client_kx_ffdh_params = pn.parameters(default_backend())
353
354    def post_dissection(self, r):
355        try:
356            self.register_pubkey()
357        except ImportError:
358            pass
359
360    def guess_payload_class(self, p):
361        """
362        The signature after the params gets saved as Padding.
363        This way, the .getfield() which _TLSServerParamsField inherits
364        from PacketField will return the signature remain as expected.
365        """
366        return Padding
367
368
369### Elliptic Curve Diffie-Hellman
370
371_tls_ec_curve_types = { 1: "explicit_prime",
372                        2: "explicit_char2",
373                        3: "named_curve" }
374
375_tls_ec_basis_types = { 0: "ec_basis_trinomial", 1: "ec_basis_pentanomial"}
376
377class ECCurvePkt(Packet):
378    name = "Elliptic Curve"
379    fields_desc = [ FieldLenField("alen", None, length_of="a", fmt="B"),
380                    StrLenField("a", "", length_from = lambda pkt: pkt.alen),
381                    FieldLenField("blen", None, length_of="b", fmt="B"),
382                    StrLenField("b", "", length_from = lambda pkt: pkt.blen) ]
383
384
385## Char2 Curves
386
387class ECTrinomialBasis(Packet):
388    name = "EC Trinomial Basis"
389    val = 0
390    fields_desc = [ FieldLenField("klen", None, length_of="k", fmt="B"),
391                    StrLenField("k", "", length_from = lambda pkt: pkt.klen) ]
392    def guess_payload_class(self, p):
393        return Padding
394
395class ECPentanomialBasis(Packet):
396    name = "EC Pentanomial Basis"
397    val = 1
398    fields_desc = [ FieldLenField("k1len", None, length_of="k1", fmt="B"),
399                    StrLenField("k1", "", length_from=lambda pkt: pkt.k1len),
400                    FieldLenField("k2len", None, length_of="k2", fmt="B"),
401                    StrLenField("k2", "", length_from=lambda pkt: pkt.k2len),
402                    FieldLenField("k3len", None, length_of="k3", fmt="B"),
403                    StrLenField("k3", "", length_from=lambda pkt: pkt.k3len) ]
404    def guess_payload_class(self, p):
405        return Padding
406
407_tls_ec_basis_cls = { 0: ECTrinomialBasis, 1: ECPentanomialBasis}
408
409class _ECBasisTypeField(ByteEnumField):
410    __slots__ = ["basis_type_of"]
411    def __init__(self, name, default, enum, basis_type_of, remain=0):
412        self.basis_type_of = basis_type_of
413        EnumField.__init__(self, name, default, enum, "B")
414
415    def i2m(self, pkt, x):
416        if x is None:
417            val = 0
418            fld,fval = pkt.getfield_and_val(self.basis_type_of)
419            x = fld.i2basis_type(pkt, fval)
420        return x
421
422class _ECBasisField(PacketField):
423    __slots__ = ["clsdict", "basis_type_from"]
424    def __init__(self, name, default, basis_type_from, clsdict, remain=0):
425        self.clsdict = clsdict
426        self.basis_type_from = basis_type_from
427        PacketField.__init__(self, name, default, None, remain=remain)
428
429    def m2i(self, pkt, m):
430        basis = self.basis_type_from(pkt)
431        cls = self.clsdict[basis]
432        return cls(m)
433
434    def i2basis_type(self, pkt, x):
435        val = 0
436        try:
437            val = x.val
438        except:
439            pass
440        return val
441
442
443## Distinct ECParameters
444##
445## To support the different ECParameters structures defined in Sect. 5.4 of
446## RFC 4492, we define 3 separates classes for implementing the 3 associated
447## ServerECDHParams: ServerECDHNamedCurveParams, ServerECDHExplicitPrimeParams
448## and ServerECDHExplicitChar2Params (support for this one is only partial).
449## The most frequent encounter of the 3 is (by far) ServerECDHNamedCurveParams.
450
451class ServerECDHExplicitPrimeParams(_GenericTLSSessionInheritance):
452    """
453    We provide parsing abilities for ExplicitPrimeParams, but there is no
454    support from the cryptography library, hence no context operations.
455    """
456    name = "Server ECDH parameters - Explicit Prime"
457    fields_desc = [ ByteEnumField("curve_type", 1, _tls_ec_curve_types),
458                    FieldLenField("plen", None, length_of="p", fmt="B"),
459                    StrLenField("p", "", length_from=lambda pkt: pkt.plen),
460                    PacketField("curve", None, ECCurvePkt),
461                    FieldLenField("baselen", None, length_of="base", fmt="B"),
462                    StrLenField("base", "",
463                                length_from=lambda pkt: pkt.baselen),
464                    FieldLenField("orderlen", None,
465                                  length_of="order", fmt="B"),
466                    StrLenField("order", "",
467                                length_from=lambda pkt: pkt.orderlen),
468                    FieldLenField("cofactorlen", None,
469                                  length_of="cofactor", fmt="B"),
470                    StrLenField("cofactor", "",
471                                length_from=lambda pkt: pkt.cofactorlen),
472                    FieldLenField("pointlen", None,
473                                  length_of="point", fmt="B"),
474                    StrLenField("point", "",
475                                length_from=lambda pkt: pkt.pointlen) ]
476
477    def fill_missing(self):
478        """
479        Note that if it is not set by the user, the cofactor will always
480        be 1. It is true for most, but not all, TLS elliptic curves.
481        """
482        if self.curve_type is None:
483            self.curve_type = _tls_ec_curve_types["explicit_prime"]
484
485    def guess_payload_class(self, p):
486        return Padding
487
488
489class ServerECDHExplicitChar2Params(_GenericTLSSessionInheritance):
490    """
491    We provide parsing abilities for Char2Params, but there is no
492    support from the cryptography library, hence no context operations.
493    """
494    name = "Server ECDH parameters - Explicit Char2"
495    fields_desc = [ ByteEnumField("curve_type", 2, _tls_ec_curve_types),
496                    ShortField("m", None),
497                    _ECBasisTypeField("basis_type", None,
498                                      _tls_ec_basis_types, "basis"),
499                    _ECBasisField("basis", ECTrinomialBasis(),
500                                  lambda pkt: pkt.basis_type,
501                                  _tls_ec_basis_cls),
502                    PacketField("curve", ECCurvePkt(), ECCurvePkt),
503                    FieldLenField("baselen", None, length_of="base", fmt="B"),
504                    StrLenField("base", "",
505                                length_from = lambda pkt: pkt.baselen),
506                    ByteField("order", None),
507                    ByteField("cofactor", None),
508                    FieldLenField("pointlen", None,
509                                  length_of="point", fmt="B"),
510                    StrLenField("point", "",
511                                length_from = lambda pkt: pkt.pointlen) ]
512
513    def fill_missing(self):
514        if self.curve_type is None:
515            self.curve_type = _tls_ec_curve_types["explicit_char2"]
516
517    def guess_payload_class(self, p):
518        return Padding
519
520
521class ServerECDHNamedCurveParams(_GenericTLSSessionInheritance):
522    name = "Server ECDH parameters - Named Curve"
523    fields_desc = [ ByteEnumField("curve_type", 3, _tls_ec_curve_types),
524                    ShortEnumField("named_curve", None, _tls_named_curves),
525                    FieldLenField("pointlen", None,
526                                  length_of="point", fmt="B"),
527                    StrLenField("point", None,
528                                length_from = lambda pkt: pkt.pointlen) ]
529
530    @crypto_validator
531    def fill_missing(self):
532        """
533        We do not want TLSServerKeyExchange.build() to overload and recompute
534        things everytime it is called. This method can be called specifically
535        to have things filled in a smart fashion.
536
537        XXX We should account for the point_format (before 'point' filling).
538        """
539        s = self.tls_session
540
541        if self.curve_type is None:
542            self.curve_type = _tls_ec_curve_types["named_curve"]
543
544        if self.named_curve is None:
545            curve = ec.SECP256R1()
546            s.server_kx_privkey = ec.generate_private_key(curve,
547                                                          default_backend())
548            curve_id = 0
549            for cid, name in six.iteritems(_tls_named_curves):
550                if name == curve.name:
551                    curve_id = cid
552                    break
553            self.named_curve = curve_id
554        else:
555            curve_name = _tls_named_curves.get(self.named_curve)
556            if curve_name is None:
557                # this fallback is arguable
558                curve = ec.SECP256R1()
559            else:
560                curve_cls = ec._CURVE_TYPES.get(curve_name)
561                if curve_cls is None:
562                    # this fallback is arguable
563                    curve = ec.SECP256R1()
564                else:
565                    curve = curve_cls()
566            s.server_kx_privkey = ec.generate_private_key(curve,
567                                                          default_backend())
568
569        if self.point is None:
570            pubkey = s.server_kx_privkey.public_key()
571            self.point = pubkey.public_numbers().encode_point()
572        # else, we assume that the user wrote the server_kx_privkey by himself
573        if self.pointlen is None:
574            self.pointlen = len(self.point)
575
576        if not s.client_kx_ecdh_params:
577            s.client_kx_ecdh_params = curve
578
579    @crypto_validator
580    def register_pubkey(self):
581        """
582        XXX Support compressed point format.
583        XXX Check that the pubkey received is on the curve.
584        """
585        #point_format = 0
586        #if self.point[0] in [b'\x02', b'\x03']:
587        #    point_format = 1
588
589        curve_name = _tls_named_curves[self.named_curve]
590        curve = ec._CURVE_TYPES[curve_name]()
591        import_point = ec.EllipticCurvePublicNumbers.from_encoded_point
592        pubnum = import_point(curve, self.point)
593        s = self.tls_session
594        s.server_kx_pubkey = pubnum.public_key(default_backend())
595
596        if not s.client_kx_ecdh_params:
597            s.client_kx_ecdh_params = curve
598
599    def post_dissection(self, r):
600        try:
601            self.register_pubkey()
602        except ImportError:
603            pass
604
605    def guess_payload_class(self, p):
606        return Padding
607
608
609_tls_server_ecdh_cls = { 1: ServerECDHExplicitPrimeParams,
610                         2: ServerECDHExplicitChar2Params,
611                         3: ServerECDHNamedCurveParams }
612
613def _tls_server_ecdh_cls_guess(m):
614    if not m:
615        return None
616    curve_type = orb(m[0])
617    return _tls_server_ecdh_cls.get(curve_type, None)
618
619
620### RSA Encryption (export)
621
622class ServerRSAParams(_GenericTLSSessionInheritance):
623    """
624    Defined for RSA_EXPORT kx : it enables servers to share RSA keys shorter
625    than their principal {>512}-bit key, when it is not allowed for kx.
626
627    This should not appear in standard RSA kx negotiation, as the key
628    has already been advertised in the Certificate message.
629    """
630    name = "Server RSA_EXPORT parameters"
631    fields_desc = [ FieldLenField("rsamodlen", None, length_of="rsamod"),
632                    StrLenField("rsamod", "",
633                                length_from = lambda pkt: pkt.rsamodlen),
634                    FieldLenField("rsaexplen", None, length_of="rsaexp"),
635                    StrLenField("rsaexp", "",
636                                length_from = lambda pkt: pkt.rsaexplen) ]
637
638    @crypto_validator
639    def fill_missing(self):
640        k = PrivKeyRSA()
641        k.fill_and_store(modulusLen=512)
642        self.tls_session.server_tmp_rsa_key = k
643        pubNum = k.pubkey.public_numbers()
644
645        if not self.rsamod:
646            self.rsamod = pkcs_i2osp(pubNum.n, k.pubkey.key_size//8)
647        if self.rsamodlen is None:
648            self.rsamodlen = len(self.rsamod)
649
650        rsaexplen = math.ceil(math.log(pubNum.e)/math.log(2)/8.)
651        if not self.rsaexp:
652            self.rsaexp = pkcs_i2osp(pubNum.e, rsaexplen)
653        if self.rsaexplen is None:
654            self.rsaexplen = len(self.rsaexp)
655
656    @crypto_validator
657    def register_pubkey(self):
658        mLen = self.rsamodlen
659        m    = self.rsamod
660        e    = self.rsaexp
661        self.tls_session.server_tmp_rsa_key = PubKeyRSA((e, m, mLen))
662
663    def post_dissection(self, pkt):
664        try:
665            self.register_pubkey()
666        except ImportError:
667            pass
668
669    def guess_payload_class(self, p):
670        return Padding
671
672
673### Pre-Shared Key
674
675class ServerPSKParams(Packet):
676    """
677    XXX We provide some parsing abilities for ServerPSKParams, but the
678    context operations have not been implemented yet. See RFC 4279.
679    Note that we do not cover the (EC)DHE_PSK key exchange,
680    which should contain a Server*DHParams after 'psk_identity_hint'.
681    """
682    name = "Server PSK parameters"
683    fields_desc = [ FieldLenField("psk_identity_hint_len", None,
684                                  length_of="psk_identity_hint", fmt="!H"),
685                    StrLenField("psk_identity_hint", "",
686                        length_from=lambda pkt: pkt.psk_identity_hint_len) ]
687
688    def fill_missing(self):
689        pass
690
691    def post_dissection(self, pkt):
692        pass
693
694    def guess_payload_class(self, p):
695        return Padding
696
697
698###############################################################################
699### Client Key Exchange value                                               ###
700###############################################################################
701
702### FFDH/ECDH
703
704class ClientDiffieHellmanPublic(_GenericTLSSessionInheritance):
705    """
706    If the user provides a value for dh_Yc attribute, we assume he will set
707    the pms and ms accordingly and trigger the key derivation on his own.
708
709    XXX As specified in 7.4.7.2. of RFC 4346, we should distinguish the needs
710    for implicit or explicit value depending on availability of DH parameters
711    in *client* certificate. For now we can only do ephemeral/explicit DH.
712    """
713    name = "Client DH Public Value"
714    fields_desc = [ FieldLenField("dh_Yclen", None, length_of="dh_Yc"),
715                    StrLenField("dh_Yc", "",
716                                length_from=lambda pkt: pkt.dh_Yclen) ]
717
718    @crypto_validator
719    def fill_missing(self):
720        s = self.tls_session
721        params = s.client_kx_ffdh_params
722        s.client_kx_privkey = params.generate_private_key()
723        pubkey = s.client_kx_privkey.public_key()
724        y = pubkey.public_numbers().y
725        self.dh_Yc = pkcs_i2osp(y, pubkey.key_size//8)
726
727        if s.client_kx_privkey and s.server_kx_pubkey:
728            pms = s.client_kx_privkey.exchange(s.server_kx_pubkey)
729            s.pre_master_secret = pms
730            s.compute_ms_and_derive_keys()
731
732    def post_build(self, pkt, pay):
733        if not self.dh_Yc:
734            try:
735                self.fill_missing()
736            except ImportError:
737                pass
738        if self.dh_Yclen is None:
739            self.dh_Yclen = len(self.dh_Yc)
740        return pkcs_i2osp(self.dh_Yclen, 2) + self.dh_Yc + pay
741
742    def post_dissection(self, m):
743        """
744        First we update the client DHParams. Then, we try to update the server
745        DHParams generated during Server*DHParams building, with the shared
746        secret. Finally, we derive the session keys and update the context.
747        """
748        s = self.tls_session
749
750        # if there are kx params and keys, we assume the crypto library is ok
751        if s.client_kx_ffdh_params:
752            y = pkcs_os2ip(self.dh_Yc)
753            param_numbers = s.client_kx_ffdh_params.parameter_numbers()
754            public_numbers = dh.DHPublicNumbers(y, param_numbers)
755            s.client_kx_pubkey = public_numbers.public_key(default_backend())
756
757        if s.server_kx_privkey and s.client_kx_pubkey:
758            ZZ = s.server_kx_privkey.exchange(s.client_kx_pubkey)
759            s.pre_master_secret = ZZ
760            s.compute_ms_and_derive_keys()
761
762    def guess_payload_class(self, p):
763        return Padding
764
765class ClientECDiffieHellmanPublic(_GenericTLSSessionInheritance):
766    """
767    Note that the 'len' field is 1 byte longer than with the previous class.
768    """
769    name = "Client ECDH Public Value"
770    fields_desc = [ FieldLenField("ecdh_Yclen", None,
771                                  length_of="ecdh_Yc", fmt="B"),
772                    StrLenField("ecdh_Yc", "",
773                                length_from=lambda pkt: pkt.ecdh_Yclen)]
774
775    @crypto_validator
776    def fill_missing(self):
777        s = self.tls_session
778        params = s.client_kx_ecdh_params
779        s.client_kx_privkey = ec.generate_private_key(params,
780                                                      default_backend())
781        pubkey = s.client_kx_privkey.public_key()
782        x = pubkey.public_numbers().x
783        y = pubkey.public_numbers().y
784        self.ecdh_Yc = (b"\x04" +
785                        pkcs_i2osp(x, params.key_size//8) +
786                        pkcs_i2osp(y, params.key_size//8))
787
788        if s.client_kx_privkey and s.server_kx_pubkey:
789            pms = s.client_kx_privkey.exchange(ec.ECDH(), s.server_kx_pubkey)
790            s.pre_master_secret = pms
791            s.compute_ms_and_derive_keys()
792
793    def post_build(self, pkt, pay):
794        if not self.ecdh_Yc:
795            try:
796                self.fill_missing()
797            except ImportError:
798                pass
799        if self.ecdh_Yclen is None:
800            self.ecdh_Yclen = len(self.ecdh_Yc)
801        return pkcs_i2osp(self.ecdh_Yclen, 1) + self.ecdh_Yc + pay
802
803    def post_dissection(self, m):
804        s = self.tls_session
805
806        # if there are kx params and keys, we assume the crypto library is ok
807        if s.client_kx_ecdh_params:
808            import_point = ec.EllipticCurvePublicNumbers.from_encoded_point
809            pub_num = import_point(s.client_kx_ecdh_params, self.ecdh_Yc)
810            s.client_kx_pubkey = pub_num.public_key(default_backend())
811
812        if s.server_kx_privkey and s.client_kx_pubkey:
813            ZZ = s.server_kx_privkey.exchange(ec.ECDH(), s.client_kx_pubkey)
814            s.pre_master_secret = ZZ
815            s.compute_ms_and_derive_keys()
816
817
818### RSA Encryption (standard & export)
819
820class _UnEncryptedPreMasterSecret(Raw):
821    """
822    When the content of an EncryptedPreMasterSecret could not be deciphered,
823    we use this class to represent the encrypted data.
824    """
825    name = "RSA Encrypted PreMaster Secret (protected)"
826    def __init__(self, *args, **kargs):
827        if 'tls_session' in kargs:
828            del(kargs['tls_session'])
829        return super(_UnEncryptedPreMasterSecret, self).__init__(*args, **kargs)
830
831class EncryptedPreMasterSecret(_GenericTLSSessionInheritance):
832    """
833    Pay attention to implementation notes in section 7.4.7.1 of RFC 5246.
834    """
835    name = "RSA Encrypted PreMaster Secret"
836    fields_desc = [ _TLSClientVersionField("client_version", None,
837                                           _tls_version),
838                    StrFixedLenField("random", None, 46) ]
839
840    @classmethod
841    def dispatch_hook(cls, _pkt=None, *args, **kargs):
842        if 'tls_session' in kargs:
843            s = kargs['tls_session']
844            if s.server_tmp_rsa_key is None and s.server_rsa_key is None:
845                return _UnEncryptedPreMasterSecret
846        return EncryptedPreMasterSecret
847
848    def pre_dissect(self, m):
849        s = self.tls_session
850        tbd = m
851        if s.tls_version >= 0x0301:
852            if len(m) < 2:      # Should not happen
853                return m
854            l = struct.unpack("!H", m[:2])[0]
855            if len(m) != l+2:
856                err = "TLS 1.0+, but RSA Encrypted PMS with no explicit length"
857                warning(err)
858            else:
859                tbd = m[2:]
860        if s.server_tmp_rsa_key is not None:
861            # priority is given to the tmp_key, if there is one
862            decrypted = s.server_tmp_rsa_key.decrypt(tbd)
863            pms = decrypted[-48:]
864        elif s.server_rsa_key is not None:
865            decrypted = s.server_rsa_key.decrypt(tbd)
866            pms = decrypted[-48:]
867        else:
868            # the dispatch_hook is supposed to prevent this case
869            pms = b"\x00"*48
870            err = "No server RSA key to decrypt Pre Master Secret. Skipping."
871            warning(err)
872
873        s.pre_master_secret = pms
874        s.compute_ms_and_derive_keys()
875
876        return pms
877
878    def post_build(self, pkt, pay):
879        """
880        We encrypt the premaster secret (the 48 bytes) with either the server
881        certificate or the temporary RSA key provided in a server key exchange
882        message. After that step, we add the 2 bytes to provide the length, as
883        described in implementation notes at the end of section 7.4.7.1.
884        """
885        enc = pkt
886
887        s = self.tls_session
888        s.pre_master_secret = enc
889        s.compute_ms_and_derive_keys()
890
891        if s.server_tmp_rsa_key is not None:
892            enc = s.server_tmp_rsa_key.encrypt(pkt, t="pkcs")
893        elif s.server_certs is not None and len(s.server_certs) > 0:
894            enc = s.server_certs[0].encrypt(pkt, t="pkcs")
895        else:
896            warning("No material to encrypt Pre Master Secret")
897
898        l = b""
899        if s.tls_version >= 0x0301:
900            l = struct.pack("!H", len(enc))
901        return l + enc + pay
902
903    def guess_payload_class(self, p):
904        return Padding
905
906
907# Pre-Shared Key
908
909class ClientPSKIdentity(Packet):
910    """
911    XXX We provide parsing abilities for ServerPSKParams, but the context
912    operations have not been implemented yet. See RFC 4279.
913    Note that we do not cover the (EC)DHE_PSK nor the RSA_PSK key exchange,
914    which should contain either an EncryptedPMS or a ClientDiffieHellmanPublic.
915    """
916    name = "Server PSK parameters"
917    fields_desc = [ FieldLenField("psk_identity_len", None,
918                                  length_of="psk_identity", fmt="!H"),
919                    StrLenField("psk_identity", "",
920                        length_from=lambda pkt: pkt.psk_identity_len) ]
921
922