Home | History | Annotate | Download | only in tls
      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 """
      7 TLS key exchange logic.
      8 """
      9 
     10 from __future__ import absolute_import
     11 import math
     12 
     13 from scapy.config import conf, crypto_validator
     14 from scapy.error import warning
     15 from scapy.fields import *
     16 from scapy.compat import orb
     17 from scapy.packet import Packet, Raw, Padding
     18 from scapy.layers.tls.cert import PubKeyRSA, PrivKeyRSA
     19 from scapy.layers.tls.session import _GenericTLSSessionInheritance
     20 from scapy.layers.tls.basefields import _tls_version, _TLSClientVersionField
     21 from scapy.layers.tls.crypto.pkcs1 import pkcs_i2osp, pkcs_os2ip
     22 from scapy.layers.tls.crypto.groups import _ffdh_groups, _tls_named_curves
     23 import scapy.modules.six as six
     24 
     25 if 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 
     55 def 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 
     68 def 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 
     83 class 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 
     89 class 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 
     95 class 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 
    102 class 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 
    117 class 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 
    132 class _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 
    202 class _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 
    230 class _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 
    274 class 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 
    377 class 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 
    387 class 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 
    395 class 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 
    409 class _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 
    422 class _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 
    451 class 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 
    489 class 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 
    521 class 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 
    613 def _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 
    622 class 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 
    675 class 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 
    704 class 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 
    765 class 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 
    820 class _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 
    831 class 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 
    909 class 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