diff --git a/.travis/install.sh b/.travis/install.sh
index 20bc9b411aa73dfc9c37547d336d8d5865c37edb..d2936ab9aa997b4450b912a637397e4bb7796450 100644
--- a/.travis/install.sh
+++ b/.travis/install.sh
@@ -10,9 +10,9 @@ fi
 
 if python --version 2>&1 | grep -q PyPy; then
   # cryptography requires PyPy >= 2.6, Travis CI uses 2.5.0
-  $SCAPY_SUDO pip install $PIP_INSTALL_FLAGS ecdsa mock
+  $SCAPY_SUDO pip install $PIP_INSTALL_FLAGS mock
 else
-  $SCAPY_SUDO pip install $PIP_INSTALL_FLAGS cryptography ecdsa mock
+  $SCAPY_SUDO pip install $PIP_INSTALL_FLAGS cryptography mock
 fi
 
 # Install coverage
@@ -26,7 +26,7 @@ if [ ! -z $SCAPY_USE_PCAPDNET ]
 then
   if [ "$TRAVIS_OS_NAME" = "linux" ]
   then
-    $SCAPY_SUDO apt-get install python-libpcap python-dumbnet
+    $SCAPY_SUDO apt-get install python-libpcap python-dumbnet openssl
   elif [ "$TRAVIS_OS_NAME" = "osx" ]
   then
     mkdir -p /Users/travis/Library/Python/2.7/lib/python/site-packages
diff --git a/.travis/test.sh b/.travis/test.sh
index 9edadf7e6b57be98be8e676949fc59052d431b5b..64ba5b1fad648301e00673297a4fc27b346afe06 100644
--- a/.travis/test.sh
+++ b/.travis/test.sh
@@ -75,3 +75,10 @@ for f in ../scapy/contrib/*.uts
 do
   $SCAPY_SUDO ./run_tests -f text -t $f $UT_FLAGS -P "load_contrib('$(basename ${f/.uts})')" || exit $?
 done
+
+# Run unit tests with openssl if we have root privileges
+if [ "$TRAVIS_OS_NAME" = "linux" ] && [ ! -z $SCAPY_USE_PCAPDNET ] && [ ! -z $SCAPY_SUDO ]
+then
+  $SCAPY_SUDO tls/run_tests_tls_netaccess || exit $?
+fi
+
diff --git a/scapy/all.py b/scapy/all.py
index 9d6e5b5d3f80e7ab619869b98242d468bcc23b18..9ad308de32d09f13ca8f795e02ddbd9c6f82b19d 100644
--- a/scapy/all.py
+++ b/scapy/all.py
@@ -38,6 +38,11 @@ from scapy.autorun import *
 from scapy.main import *
 
 from scapy.layers.all import *
+if "tls" in conf.load_layers:
+    try:
+        from scapy.layers.tls.all import *
+    except ImportError:
+        pass
 
 from scapy.asn1.asn1 import *
 from scapy.asn1.ber import *
diff --git a/scapy/asn1/mib.py b/scapy/asn1/mib.py
index 5506c0f99f479292a800ae67467ba4887ce5e184..59dc5b9617e728b881f39d9ddb25f00ad73c07ec 100644
--- a/scapy/asn1/mib.py
+++ b/scapy/asn1/mib.py
@@ -169,6 +169,12 @@ pkcs1_oids = {
         "sha224WithRSAEncryption"           : "1.2.840.113549.1.1.14"
         }
 
+####### secsig oiw #######
+
+secsig_oids = {
+        "sha1"                              : "1.3.14.3.2.26"
+        }
+
 ####### pkcs9 #######
 
 pkcs9_oids = {
@@ -428,7 +434,8 @@ certPkixAd_oids = {
         "id-ad-caRepository"            : "1.3.6.1.5.5.7.48.5",
         "id-pkix-ocsp-archive-cutoff"   : "1.3.6.1.5.5.7.48.6",
         "id-pkix-ocsp-service-locator"  : "1.3.6.1.5.5.7.48.7",
-        "id-ad-cmc"                     : "1.3.6.1.5.5.7.48.12"
+        "id-ad-cmc"                     : "1.3.6.1.5.5.7.48.12",
+        "basic-response"                : "1.3.6.1.5.5.7.48.1.1"
         }
 
 ####### ansi-x962 #######
@@ -556,6 +563,7 @@ evPolicy_oids = {
 
 x509_oids_sets = [
                  pkcs1_oids,
+                 secsig_oids,
                  pkcs9_oids,
                  attributeType_oids,
                  certificateExtension_oids,
diff --git a/scapy/config.py b/scapy/config.py
index 6f1f9787569350b1842f3d77f3d1f650d0d034da..e46ffeadc2f0dc97eaaf05426445cc471bae8839 100755
--- a/scapy/config.py
+++ b/scapy/config.py
@@ -310,7 +310,7 @@ def _prompt_changer(attr,val):
 class Conf(ConfClass):
     """This object contains the configuration of Scapy.
 session  : filename where the session will be saved
-interactive_shell : If set to "ipython", use IPython as shell. Default: Python 
+interactive_shell : If set to "ipython", use IPython as shell. Default: Python
 stealth  : if 1, prevents any unwanted packet to go out (ARP, DNS, ...)
 checkIPID: if 0, doesn't check that IPID matches between IP sent and ICMP IP citation received
            if 1, checks that they either are equal or byte swapped equals (bug in some IP stacks)
@@ -332,11 +332,12 @@ route    : holds the Scapy routing table and provides methods to manipulate it
 warning_threshold : how much time between warnings from the same place
 ASN1_default_codec: Codec used by default for ASN1 objects
 mib      : holds MIB direct access dictionary
-resolve   : holds list of fields for which resolution should be done
-noenum    : holds list of enum fields for which conversion to string should NOT be done
+resolve  : holds list of fields for which resolution should be done
+noenum   : holds list of enum fields for which conversion to string should NOT be done
 AS_resolver: choose the AS resolver class to use
 extensions_paths: path or list of paths where extensions are to be looked for
-contribs: a dict which can be used by contrib layers to store local configuration
+contribs : a dict which can be used by contrib layers to store local configuration
+debug_tls:When 1, print some TLS session secrets when they are computed.
 """
     version = VERSION
     session = ""
@@ -373,6 +374,7 @@ contribs: a dict which can be used by contrib layers to store local configuratio
     padding = 1
     except_filter = ""
     debug_match = 0
+    debug_tls = 0
     wepkey = ""
     route = None # Filed by route.py
     route6 = None # Filed by route6.py
diff --git a/scapy/fields.py b/scapy/fields.py
index 53f84727ca737ee33fc52d11438303d2aefc7554..8ec15ef9148e91e096fc39143f26aca00fb905cc 100644
--- a/scapy/fields.py
+++ b/scapy/fields.py
@@ -622,7 +622,11 @@ class FieldListField(Field):
         else:
             return map(lambda e, pkt=pkt: self.field.any2i(pkt, e), x)
     def i2repr(self, pkt, x):
-        return map(lambda e, pkt=pkt: self.field.i2repr(pkt,e), x)
+        res = []
+        for v in x:
+            r = self.field.i2repr(pkt, v)
+            res.append(r)
+        return "[%s]" % ", ".join(res)
     def addfield(self, pkt, s, val):
         val = self.i2m(pkt, val)
         for v in val:
diff --git a/scapy/layers/all.py b/scapy/layers/all.py
index 1774049421bfa2731d5a261a06dda00a54e15f9b..f23fae1c3d0a0bcc286b438bf076ba8647e9d4c8 100644
--- a/scapy/layers/all.py
+++ b/scapy/layers/all.py
@@ -31,6 +31,8 @@ def _import_star(m):
 for _l in conf.load_layers:
     log_loading.debug("Loading layer %s" % _l)
     try:
-        _import_star(_l)
+        if _l != "tls":
+            _import_star(_l)
     except Exception,e:
         log.warning("can't import layer %s: %s" % (_l,e))
+
diff --git a/scapy/layers/tls/__init__.py b/scapy/layers/tls/__init__.py
index 2f20630887846cc99eb5259ebc8ed45c5d589353..2c6159194a86c9b68690c2a697c9eed1fd214fef 100644
--- a/scapy/layers/tls/__init__.py
+++ b/scapy/layers/tls/__init__.py
@@ -1,10 +1,114 @@
 ## This file is part of Scapy
-## See http://www.secdev.org/projects/scapy for more informations
-## Copyright (C) Arnaud Ebalard, Maxence Tury
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard <arno@natisbad.com>
+##                     2015, 2016 Maxence Tury <maxence.tury@ssi.gouv.fr>
 ## This program is published under a GPLv2 license
 
 """
 Tools for handling TLS sessions and digital certificates.
+
+Prerequisites:
+
+    - You may need to 'pip install cryptography' for the module to be loaded.
+
+
+Main features:
+
+    - X.509 certificates parsing/building.
+
+    - RSA & ECDSA keys sign/verify methods.
+
+    - TLS records and sublayers (handshake...) parsing/building. Works with
+      versions SSLv3, TLS 1.0, 1.1 and 1.2. This may be enhanced by a TLS
+      context. For instance, if scapy reads a ServerHello with version TLS 1.2
+      and a cipher suite using AES, it will assume the presence of IVs
+      prepending the data. See test/tls.uts for real examples.
+
+    - TLS encryption/decryption capabilities with the usual ciphersuites. Once
+      again, the TLS context enables scapy to transparently send/receive
+      protected data if it learnt the session secrets. Note that if scapy acts
+      as one side of the handshake (e.g. reads all server-related packets and
+      builds all client-related packets), it will indeed compute the session
+      secrets.
+
+    - TLS client & server basic automatons, provided for testing and tweaking
+      purposes. These make for a very primitive TLS stack.
+
+    - Additionally, a basic test PKI (key + certificate for a CA, a client and
+      a server) is provided in tls/examples/pki_test.
+
+
+Unit tests:
+
+    - Various cryptography checks.
+
+    - Reading a TLS handshake between a Firefox client and a GitHub server.
+
+    - Test our TLS server against s_client with different cipher suites.
+
+    - Test our TLS client against our TLS server (s_server is unscriptable).
+
+
+TODO list (may it be carved away by good souls):
+
+    - Features to add (or wait for) in the cryptography library:
+
+        - no limitation on FFDH generator size;
+          (remove line 88 in cryptography/hazmat/primitives/asymmetric/dh.py)
+
+        - CCM and CHACHA20-POLY1305 ciphers;
+
+        - ECDH curves (x25519 and x448) from RFC 7748;
+
+        - FFDH groups from RFC 7919;
+
+        - the so-called 'tls' hash used with SSLv3 and TLS 1.0;
+
+        - the simple DES algorithm;
+
+        - the compressed EC point format.
+
+
+    - About the automatons:
+
+        - Enrich the automatons. The client should be able to receive data at
+          any time, and to send as much data as wanted from stdin (for now,
+          only one predefined data message may be sent following the
+          handshake). The server should stay online even after the first client
+          leaves. Then we could look at more complicated behaviours like
+          renegotiation and resumption. We might get some help from
+          tintinweb/scapy-ssl_tls.
+
+        - Add some examples which illustrate how the automatons could be used.
+          Typically, we could showcase this with Heartbleed.
+
+        - Split up parts of the automaton, e.g. when our server builds the
+          ServerHello, Certificate, ServerKeyExchange and ServerHelloDone in
+          the same should_REPLY_TO_CH method.
+
+        - Make the automatons tests more robust and less consuming.
+
+        - Allow the server to store both one RSA key and one ECDSA key, and
+          select the right one to use according to the ClientHello suites.
+
+        - Find a way to shutdown the automatons sockets properly without
+          simultaneously breaking the unit tests.
+
+
+    - Miscellaneous:
+
+        - Implement TLS 1.3 structures and automatons. :D
+
+        - Implement SSLv2 structures and automatons. xD
+
+        - Mostly unused features : DSS, fixed DH, SRP, IDEA, char2 curves...
+
+        - Check FFDH and ECDH parameters at SKE/CKE reception.
+
+        - Go through the kx_algs and see what may be commented out.
+
+        - Define several Certificate Transparency objects.
+
+        - Enhance PSK and session ticket support.
 """
 
 from scapy.config import conf
@@ -12,13 +116,6 @@ from scapy.config import conf
 if not conf.crypto_valid:
     import logging
     log_loading = logging.getLogger("scapy.loading")
-    log_loading.info("Can't import python-cryptography v1.7+. Disabled PKCS #1 signing/verifying.")
+    log_loading.info("Can't import python-cryptography v1.7+. "
+                     "Disabled PKI & TLS crypto-related features.")
 
-try:
-    import ecdsa
-except ImportError:
-    import logging
-    log_loading = logging.getLogger("scapy.loading")
-    log_loading.info("Can't import python ecdsa lib. Disabled certificate manipulation tools")
-else:
-    from scapy.layers.tls.cert import *
diff --git a/scapy/layers/tls/all.py b/scapy/layers/tls/all.py
new file mode 100644
index 0000000000000000000000000000000000000000..3409b88c4f3af36de1798da23e2922c71cec3b74
--- /dev/null
+++ b/scapy/layers/tls/all.py
@@ -0,0 +1,19 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+Aggregate top level objects from all TLS modules.
+"""
+
+from scapy.layers.tls.cert import *
+
+from scapy.layers.tls.automaton import *
+from scapy.layers.tls.handshake import *
+from scapy.layers.tls.keyexchange import *
+from scapy.layers.tls.record import *
+from scapy.layers.tls.session import *
+
+from scapy.layers.tls.crypto.all import *
+
diff --git a/scapy/layers/tls/automaton.py b/scapy/layers/tls/automaton.py
new file mode 100644
index 0000000000000000000000000000000000000000..f31c1f1b03c7358ba8671823a1e71d74acc21caf
--- /dev/null
+++ b/scapy/layers/tls/automaton.py
@@ -0,0 +1,1078 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+TLS automatons. This makes for a primitive TLS stack.
+SSLv3 is not guaranteed, and SSLv2 is not supported.
+Obviously you need rights for network access.
+
+
+Launch a server on tcp/4433:
+
+from scapy.all import *
+t = TLSServerAutomaton(mycert='<cert.pem>', mykey='<key.pem>')
+t.run()
+
+
+Launch a client to tcp/50000 with one cipher suite of your choice:
+
+from scapy.all import *
+ch = TLSClientHello(ciphers=<int code of the cipher suite>)
+t = TLSClientAutomaton(dport=50000, client_hello=ch)
+t.run()
+"""
+
+import socket
+import struct
+
+from scapy.error import warning
+from scapy.automaton import Automaton, ATMT
+from scapy.layers.tls.cert import Cert, PrivKey, PrivKeyRSA, PrivKeyECDSA
+from scapy.layers.tls.basefields import _tls_version
+from scapy.layers.tls.session import tlsSession
+from scapy.layers.tls.handshake import *
+from scapy.layers.tls.record import (TLS, TLSAlert, TLSChangeCipherSpec,
+                                     TLSApplicationData)
+from scapy.layers.tls.crypto.suites import (_tls_cipher_suites_cls,
+                                            _tls_cipher_suites,
+                                            get_usable_ciphersuites)
+
+
+###############################################################################
+### Client automaton                                                        ###
+###############################################################################
+
+class TLSClientAutomaton(Automaton):
+    """
+    The TLS client automaton.
+
+    - server : default value is '127.0.0.1';
+    - dport : default value is 4433;
+    - server_name : default value is None;
+    - mycert : optional when there is no client authentication;
+    - mykey : optional when there is no client authentication;
+    - client_hello : optional definition of the ClientHello to be sent to the
+      server, this is faster than automaton overloading and enables quick
+      cipher suite choice (make sure it is usable, though);
+    - data : optional application_data to be sent after the handshake, if this
+      is not defined we send a simple GET request.
+    """
+
+    def parse_args(self, server="127.0.0.1", dport=4433,
+                   server_name=None, mycert=None, mykey=None,
+                   client_hello=None, data=None, **kargs):
+        Automaton.parse_args(self, **kargs)
+
+        tmp = socket.getaddrinfo(server, dport)
+        self.remote_name = None
+        try:
+            if ':' in server:
+                socket.inet_pton(socket.AF_INET6, server)
+            else:
+                socket.inet_pton(socket.AF_INET, server)
+        except:
+            self.remote_name = socket.getfqdn(server)
+            if self.remote_name != server:
+                tmp = socket.getaddrinfo(self.remote_name, dport)
+
+        if server_name:
+            self.remote_name = server_name
+        self.remote_family = tmp[0][0]
+        self.remote_ip = tmp[0][4][0]
+        self.remote_port = dport
+        self.local_ip = None
+        self.local_port = None
+
+        self.cur_pkt = None
+        self.cur_session = None
+        self.msg_list = []
+
+        self.remain = ""
+
+        self.socket = None
+
+        self.cert_req = None
+
+        self.client_hello = client_hello
+        self.data = data
+
+        if mycert and mykey:
+            self.mycert = Cert(mycert)
+            self.mykey  = PrivKey(mykey)
+        else:
+            self.mycert = None
+            self.mykey  = None
+
+
+    def get_next_msg(self, socket_timeout=5, retry=5):
+        """
+        The purpose of the function is to make next message(s) available in
+        self.msg_list. If the list is not empty, nothing is done. If not, in
+        order to fill it, the function uses the data already available in
+        self.remain from a previous call and waits till there are enough to
+        dissect a TLS packet (expected length is in the 5 first bytes of the
+        packet). Once dissected, the content of the TLS packet (carried
+        messages) is appended to self.msg_list.
+
+        We have to grab enough data to dissect a TLS packet, i.e. at least
+        5 bytes in order to access the expected length of the TLS packet.
+        """
+
+        if self.msg_list:       # a message is already available
+            return
+
+        self.socket.settimeout(socket_timeout)
+        grablen = 5
+        while retry and (grablen == 5 or len(self.remain) < grablen):
+            if grablen == 5 and len(self.remain) >= 5:
+                grablen = struct.unpack('!H', self.remain[3:5])[0] + 5
+
+            if grablen == len(self.remain):
+                break
+
+            try:
+                tmp = self.socket.recv(grablen - len(self.remain))
+                if not tmp:
+                    retry -= 1
+                else:
+                    self.remain += tmp
+            except:
+                retry -= 1
+
+        if self.remain < 5 or len(self.remain) != grablen:
+            # Remote peer is not willing to respond
+            return
+
+        # Instantiate the TLS packet (record header only, at this point)
+        p = TLS(self.remain, tls_session=self.cur_session)
+        self.cur_session = p.tls_session
+        self.remain = ""
+        self.msg_list += p.msg
+
+        while p.payload:
+            if isinstance(p.payload, Raw):
+                self.remain += p.payload.load
+                p = p.payload
+            elif isinstance(p.payload, TLS):
+                p = p.payload
+                self.msg_list += p.msg
+
+
+    @ATMT.state(initial=True)
+    def INITIAL(self):
+        raise self.INIT_TLS_SESSION()
+
+    @ATMT.state()
+    def INIT_TLS_SESSION(self):
+        self.cur_session = tlsSession()
+        self.cur_session.client_certs = self.mycert
+        self.cur_session.client_key = self.mykey
+        raise self.CONNECT()
+
+    @ATMT.state()
+    def CONNECT(self):
+        s = socket.socket(self.remote_family, socket.SOCK_STREAM)
+        s.connect((self.remote_ip, self.remote_port))
+        self.socket = s
+        self.local_ip, self.local_port = self.socket.getsockname()[:2]
+        raise self.PREPARE_FIRST_PKT()
+
+    @ATMT.state()
+    def PREPARE_FIRST_PKT(self):
+        self.cur_pkt = TLS(tls_session=self.cur_session)
+
+    @ATMT.condition(PREPARE_FIRST_PKT)
+    def should_add_ClientHello(self):
+        raise self.ADDED_ClientHello()
+
+    @ATMT.action(should_add_ClientHello, prio=1)
+    def add_ClientHello(self):
+        """
+        Default TLSClientHello() offers only TLS_DHE_RSA_WITH_AES_128_CBC_SHA.
+
+        For fast server testing, typical alternatives (DHE only, RSAkx with CBC
+        only, ECDHE with appropriate extensions) may be found in tls.uts,
+        and then brought here through the client_hello argument.
+        """
+        p = self.client_hello or TLSClientHello()
+        self.cur_pkt.msg.append(p)
+
+    @ATMT.state()
+    def ADDED_ClientHello(self):
+        pass
+
+    @ATMT.condition(ADDED_ClientHello)
+    def should_send_ClientHello(self):
+        raise self.SENT_ClientHello()
+
+    @ATMT.action(should_send_ClientHello, prio=1)
+    def send_ClientHello(self):
+        self.socket.send(str(self.cur_pkt))
+        self.cur_pkt = None
+
+    @ATMT.state()
+    def SENT_ClientHello(self):
+        raise self.WAITING_FOR_ServerHello()
+
+    @ATMT.state()
+    def WAITING_FOR_ServerHello(self):
+        self.get_next_msg()
+        raise self.PREPROCESS_ServerHello()
+
+    @ATMT.state()
+    def PREPROCESS_ServerHello(self):
+        pass
+
+    @ATMT.condition(PREPROCESS_ServerHello, prio=1)
+    def should_HANDLE_ServerHello(self):
+        """
+        XXX We should check the ServerHello attributes for discrepancies with
+        our own ClientHello.
+        """
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSServerHello)):
+            return
+        p = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+        raise self.HANDLE_SH()
+
+    @ATMT.state()
+    def HANDLE_SH(self):
+        pass
+
+    @ATMT.condition(PREPROCESS_ServerHello, prio=2)
+    def missing_server_hello(self):
+        raise self.MISSING_SH()
+
+    @ATMT.state(final=True)
+    def MISSING_SH(self):
+        print "Missing TLS Server Hello message"
+
+    @ATMT.condition(HANDLE_SH, prio=1)
+    def should_HANDLE_CERT(self):
+        self.get_next_msg()
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSCertificate)):
+            return
+        p = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+        raise self.HANDLE_CERT()
+
+    @ATMT.state()
+    def HANDLE_CERT(self):
+        pass
+
+    @ATMT.condition(HANDLE_SH, prio=2)
+    def missing_certificate(self):
+        raise self.MISSING_CERT()
+
+    @ATMT.state(final=True)
+    def MISSING_CERT(self):
+        print "Missing TLS Certificate message"
+
+    @ATMT.state()
+    def HANDLE_CERT_REQ(self):
+        pass
+
+    @ATMT.condition(HANDLE_CERT, prio=1)
+    def should_HANDLE_SKE_from_CERT(self):
+        """
+        XXX We should check the ServerKeyExchange attributes for discrepancies
+        with our own ClientHello, along with the ServerHello and Certificate.
+        """
+        self.get_next_msg()
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSServerKeyExchange)):
+            return
+        p = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+        raise self.HANDLE_SKE()
+
+    @ATMT.state(final=True)
+    def MISSING_SKE(self):
+        pass
+
+    @ATMT.condition(HANDLE_CERT, prio=2)
+    def expected_server_key_exchange(self):
+        if self.cur_session.prcs.key_exchange.server_kx_msg_cls:
+            # Should have received a SKE
+            raise self.MISSING_SKE()
+
+    @ATMT.state()
+    def HANDLE_SKE(self):
+        # XXX Move that refill code somewhere else
+        self.get_next_msg()
+
+    @ATMT.condition(HANDLE_SKE, prio=2)
+    def should_HANDLE_CERT_REQ_from_SKE(self):
+        self.get_next_msg()
+        """
+        XXX We should check the CertificateRequest attributes for discrepancies
+        with the cipher suite, etc.
+        """
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSCertificateRequest)):
+            return
+        p = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+        self.cert_req = p
+        raise self.HANDLE_CERT_REQ()
+
+    @ATMT.condition(HANDLE_CERT, prio=3)
+    def should_HANDLE_CERT_REQ(self):
+        """
+        XXX We should check the CertificateRequest attributes for discrepancies
+        with the cipher suite, etc.
+        """
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSCertificateRequest)):
+            return
+        p = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+        self.cert_req = p
+        raise self.HANDLE_CERT_REQ()
+
+    @ATMT.condition(HANDLE_SKE, prio=1)
+    def should_HANDLE_SHD(self):
+        self.get_next_msg()
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSServerHelloDone)):
+            return
+        p = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+        raise self.HANDLE_SHD()
+
+    @ATMT.condition(HANDLE_CERT_REQ, prio=4)
+    def should_HANDLE_SHD_from_CERT_REQ(self):
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSServerHelloDone)):
+            return
+        p = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+        raise self.HANDLE_SHD()
+
+    @ATMT.condition(HANDLE_CERT)
+    def should_HANDLE_SHD_from_CERT(self):
+        self.get_next_msg()
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSServerHelloDone)):
+            return
+        p = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+        raise self.HANDLE_SHD()
+
+    @ATMT.state()
+    def HANDLE_SHD(self):
+        raise self.PREPARE_PKT2()
+
+    # Second packet sent by us
+    @ATMT.state()
+    def PREPARE_PKT2(self):
+        pass
+
+    @ATMT.condition(PREPARE_PKT2, prio=1)
+    def should_ADD_CLIENT_CERT(self):
+        """
+        If the server sent a CertificateRequest, we send a Certificate message.
+        If no certificate is available, an empty Certificate message is sent:
+        - this is a SHOULD in RFC 4346 (Section 7.4.6)
+        - this is a MUST in RFC 5246 (Section 7.4.6)
+
+        XXX We may want to add a complete chain.
+        """
+        if not self.cert_req:
+            return
+        certs = []
+        if self.mycert:
+            certs = [self.mycert]
+        self.cur_pkt = TLS(tls_session=self.cur_session, msg=[])
+        p = TLSCertificate(certs=certs)
+        self.cur_pkt.msg.append(p)
+        self.socket.send(str(self.cur_pkt))
+        self.cur_pkt = None
+        raise self.ADD_CLIENT_CERT()
+
+    @ATMT.state()
+    def ADD_CLIENT_CERT(self):
+        pass
+
+    @ATMT.condition(PREPARE_PKT2, prio=2)
+    def should_ADD_CKE_from_PREPARE_PKT2(self):
+        self.cur_pkt = TLS(tls_session=self.cur_session, msg=[])
+        p = TLSClientKeyExchange()
+        self.cur_pkt.msg.append(p)
+        self.socket.send(str(self.cur_pkt))
+        self.cur_pkt = None
+        raise self.ADD_CKE()
+
+    @ATMT.condition(ADD_CLIENT_CERT, prio=2)
+    def should_ADD_CKE_from_ADD_CLIENT_CERT(self):
+        self.cur_pkt = TLS(tls_session=self.cur_session, msg=[])
+        p = TLSClientKeyExchange()
+        self.cur_pkt.msg.append(p)
+        self.socket.send(str(self.cur_pkt))
+        self.cur_pkt = None
+        raise self.ADD_CKE()
+
+    @ATMT.state()
+    def ADD_CKE(self):
+        pass
+
+    @ATMT.condition(ADD_CKE, prio=1)
+    def should_ADD_CV_from_ADD_CKE(self):
+        """
+        XXX Section 7.4.7.1 of RFC 5246 states that the CertificateVerify
+        message is only sent following a client certificate that has signing
+        capability (i.e. not those containing fixed DH params).
+        We should verify that before adding the message. We should also handle
+        the case when the Certificate message was empty.
+        """
+        if (not self.cert_req or
+            self.mycert is None or
+            self.mykey is None):
+            return
+        self.cur_pkt = TLS(tls_session=self.cur_session, msg=[])
+        p = TLSCertificateVerify()
+        self.cur_pkt.msg.append(p)
+        self.socket.send(str(self.cur_pkt))
+        self.cur_pkt = None
+        raise self.ADD_CV()
+
+    @ATMT.state()
+    def ADD_CV(self):
+        pass
+
+    @ATMT.condition(ADD_CV)
+    def should_ADD_CCS_from_ADD_CV(self):
+        self.cur_pkt = TLS(type=20, tls_session=self.cur_session, msg=[])
+        p = TLSChangeCipherSpec()
+        self.cur_pkt.msg.append(p)
+        self.socket.send(str(self.cur_pkt))
+        self.cur_pkt = None
+        raise self.ADD_CCS()
+
+    @ATMT.condition(ADD_CKE, prio=2)
+    def should_ADD_CCS_from_ADD_CKE(self):
+        self.cur_pkt = TLS(type=20, tls_session=self.cur_session, msg=[])
+        p = TLSChangeCipherSpec()
+        self.cur_pkt.msg.append(p)
+        self.socket.send(str(self.cur_pkt))
+        self.cur_pkt = None
+        raise self.ADD_CCS()
+
+    @ATMT.state()
+    def ADD_CCS(self):
+        pass
+
+    @ATMT.condition(ADD_CCS)
+    def should_ADD_FINISHED(self):
+        self.cur_pkt = TLS(tls_session=self.cur_session, msg=[])
+        p = TLSFinished()
+        self.cur_pkt.msg.append(p)
+        self.socket.send(str(self.cur_pkt))
+        self.cur_pkt = None
+        raise self.ADD_FINISHED()
+
+    @ATMT.state()
+    def ADD_FINISHED(self):
+        pass
+
+    @ATMT.condition(ADD_FINISHED)
+    def should_SEND_SECOND_PKT(self):
+        raise self.SEND_SECOND_PKT()
+
+    @ATMT.state()
+    def SEND_SECOND_PKT(self):
+        raise self.WAIT_FOR_RESP2()
+
+    @ATMT.state()
+    def WAIT_FOR_RESP2(self):
+        self.socket.settimeout(10)
+        s = self.socket.recv(100000)
+        p = TLS(s, tls_session=self.cur_session)
+        self.msg_list = p.msg
+        while p.payload:
+            if isinstance(p.payload, Raw):
+                self.remain += p.payload.load
+                p = p.payload
+            elif isinstance(p.payload, TLS):
+                p = p.payload
+                self.msg_list += p.msg
+        raise self.PREPROCESS_RESP2()
+
+    # Second response from the server
+    @ATMT.state()
+    def PREPROCESS_RESP2(self):
+        pass
+
+    @ATMT.condition(PREPROCESS_RESP2)
+    def should_HANDLE_CCS(self):
+        self.get_next_msg()
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSChangeCipherSpec)):
+            return
+        p = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+        raise self.HANDLE_CCS()
+
+    @ATMT.state()
+    def HANDLE_CCS(self):
+        pass
+
+    @ATMT.condition(HANDLE_CCS)
+    def should_HANDLE_FINISHED(self):
+        self.get_next_msg()
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSFinished)):
+            return
+        p = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+        raise self.HANDLE_FINISHED()
+
+    @ATMT.state()
+    def HANDLE_FINISHED(self):
+        pass
+
+    @ATMT.condition(HANDLE_FINISHED)
+    def should_test_connection(self):
+        raise self.TESTED_CONNECTION()
+
+    @ATMT.action(should_test_connection, prio=1)
+    def send_recv_data(self):
+        """
+        XXX No live input from the user ; one unique send for now.
+        XXX We might want not to send any ApplicationData message.
+        XXX We do not wait very long for server answer.
+        """
+        txt = self.data or "GET /\r\n\r\n"  # GET HTTP/1.1\r\n\r\n"
+        p = TLS(type=23, tls_session=self.cur_session, msg=[Raw(load=txt)])
+        self.socket.send(str(p))
+        print "Sent to server: \n%r" % txt
+
+        self.get_next_msg(1, 0)
+        if self.msg_list:
+            p = self.msg_list[0]
+            self.msg_list = self.msg_list[1:]
+            if isinstance(p, Raw):
+                print "Received from server: \n%s" % p.load
+            else:
+                print "Received from server: \n%s" % p
+
+    @ATMT.state()
+    def TESTED_CONNECTION(self):
+        pass
+
+    @ATMT.condition(TESTED_CONNECTION)
+    def should_close_session(self):
+        raise self.CLOSED_TLS_SESSION()
+
+    @ATMT.action(should_close_session, prio=1)
+    def close_session(self):
+        """
+        We end the session properly after 2 seconds,
+        with a TLS Alert (warning, close_notify).
+        """
+        time.sleep(2)
+        self.cur_pkt = TLS(type=21, msg=[], tls_session=self.cur_session)
+        p = TLSAlert(level=1, descr=0)
+        self.cur_pkt.msg.append(p)
+        try:
+            self.socket.send(str(self.cur_pkt))
+        except:
+            print "Could not send termination Alert (maybe the server stopped)"
+        self.cur_pkt = None
+
+    @ATMT.state()
+    def CLOSED_TLS_SESSION(self):
+        raise self.FINAL()
+
+    @ATMT.state(final=True)
+    def FINAL(self):
+        """
+        We might call shutdown, but it may happen that the server
+        did not wait for us to shutdown after answering our data query.
+        #self.socket.shutdown(1)
+        """
+        self.socket.close()
+
+
+###############################################################################
+### Server automaton                                                        ###
+###############################################################################
+
+class TLSServerAutomaton(Automaton):
+    """
+    The TLS client automaton.
+
+    - server : default value is '127.0.0.1';
+    - sport : default value is 4433;
+    - mycert : optional when there is no client authentication;
+    - mykey : optional when there is no client authentication;
+    - preferred_ciphersuite : optional cipher suite to be selected should the
+      client offer it through its ClientHello.
+    """
+
+    def parse_args(self, server="127.0.0.1", sport=4433,
+                   mycert=None, mykey=None,
+                   preferred_ciphersuite=None, **kargs):
+        Automaton.parse_args(self, **kargs)
+
+        self.mycert = Cert(mycert)
+        self.mykey  = PrivKey(mykey)
+
+        try:
+            if ':' in server:
+                socket.inet_pton(socket.AF_INET6, server)
+            else:
+                socket.inet_pton(socket.AF_INET, server)
+            tmp = socket.getaddrinfo(server, sport)
+        except:
+            tmp = socket.getaddrinfo(socket.getfqdn(server), sport)
+
+        self.ip_family = tmp[0][0]
+        self.local_ip = tmp[0][4][0]
+        self.local_port = sport
+        self.remote_ip = None
+        self.remote_port = None
+
+        self.cur_pkt = None
+        self.cur_session = None
+        self.msg_list = []
+
+        self.remain = ""
+
+        self.socket = None
+
+        self.cert_req = None
+
+        self.preferred_ciphersuite = preferred_ciphersuite
+
+
+    def get_next_msg(self):
+        """
+        The purpose of the function is to make next message(s) available
+        in self.msg_list. If the list is not empty, nothing is done. If
+        not, in order to fill it, the function uses the data already
+        available in self.remain from a previous call and waits till there
+        are enough to dissect a TLS packet (expected length is in the 5
+        first bytes of the packet). Once dissected, the content of the
+        TLS packet (carried messages) is appended to self.msg_list.
+
+        We have to grab enough data to dissect a TLS packet, i.e. at least
+        5 bytes in order to access the expected length of the TLS packet.
+        """
+
+        if self.msg_list:       # a message is already available
+            return
+
+        self.socket.settimeout(5)
+        retry = 5
+        grablen = 5
+        while retry and (grablen == 5 or len(self.remain) < grablen):
+            if grablen == 5 and len(self.remain) >= 5:
+                grablen = struct.unpack('!H', self.remain[3:5])[0] + 5
+            if grablen == len(self.remain):
+                break
+
+            try:
+                tmp = self.socket.recv(grablen - len(self.remain))
+                if not tmp:
+                    retry -= 1
+                else:
+                    self.remain += tmp
+            except:
+                retry -= 1
+
+        if self.remain < 5 or len(self.remain) != grablen:
+            # Remote peer is not willing to respond
+            return
+
+        # Instantiate TLS packet (record header only, at this point)
+        p = TLS(self.remain, tls_session=self.cur_session)
+        self.cur_session = p.tls_session
+        self.remain = ""
+        self.msg_list += p.msg
+
+        while p.payload:
+            if isinstance(p.payload, Raw):
+                self.remain += p.payload.load
+                p = p.payload
+            elif isinstance(p.payload, TLS):
+                p = p.payload
+                self.msg_list += p.msg
+
+    @ATMT.state(initial=True)
+    def INITIAL(self):
+        raise self.INIT_TLS_SESSION()
+
+    @ATMT.state()
+    def INIT_TLS_SESSION(self):
+        """
+        XXX We should offer the right key according to the client's suites. For
+        now server_rsa_key is only used for RSAkx, but we should try to replace
+        every server_key with both server_rsa_key and server_ecdsa_key.
+        """
+        self.cur_session = tlsSession(connection_end="server")
+        self.cur_session.server_certs = [self.mycert]
+        self.cur_session.server_key = self.mykey
+        if isinstance(self.mykey, PrivKeyRSA):
+            self.cur_session.server_rsa_key = self.mykey
+        #elif isinstance(self.mykey, PrivKeyECDSA):
+        #    self.cur_session.server_ecdsa_key = self.mykey
+        raise self.BIND_AND_WAIT()
+
+    @ATMT.state()
+    def BIND_AND_WAIT(self):
+        s = socket.socket(self.ip_family, socket.SOCK_STREAM)
+        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        try:
+            s.bind((self.local_ip, self.local_port))
+            s.listen(1)
+        except:
+            print "Unable to bind on address %s and port %d" % (self.local_ip,
+                                                                self.local_port)
+            return
+        self.socket, addr = s.accept()
+        self.remote_ip, self.remote_port = addr
+
+        raise self.WAITING_FOR_ClientHello()
+
+    @ATMT.state()
+    def WAITING_FOR_ClientHello(self):
+        self.get_next_msg()
+
+        raise self.PREPROCESS_ClientHello()
+
+    @ATMT.state()
+    def PREPROCESS_ClientHello(self):
+        pass
+
+    @ATMT.condition(PREPROCESS_ClientHello, prio=1)
+    def should_HANDLE_ClientHello(self):
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSClientHello)):
+            return
+        self.cur_pkt = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+        raise self.HANDLE_CH()
+
+    @ATMT.state()
+    def HANDLE_CH(self):
+        pass
+
+    @ATMT.condition(HANDLE_CH, prio=1)
+    def should_NO_USABLE_CIPHERSUITE(self):
+        """
+        We extract cipher suites candidates from the client's proposition.
+        """
+        l = self.cur_pkt.ciphers
+
+        if isinstance(self.mykey, PrivKeyRSA):
+            kx = "RSA"
+        elif isinstance(self.mykey, PrivKeyECDSA):
+            kx = "ECDSA"
+        l = get_usable_ciphersuites(l, kx)
+
+        if l:
+            return
+
+        raise self.NO_USABLE_CIPHERSUITE()
+
+    @ATMT.state(final=True)
+    def NO_USABLE_CIPHERSUITE(self):
+        """
+        If there is no available cipher suite, close the session with an Alert.
+        """
+        print "No usable cipher suite, closing connection"
+        self.cur_pkt = TLS(type=21, msg=[], tls_session=self.cur_session)
+        p = TLSAlert(level=1, descr=0)
+        self.cur_pkt.msg.append(p)
+        self.socket.send(str(self.cur_pkt))
+        self.cur_pkt = None
+
+    @ATMT.condition(PREPROCESS_ClientHello, prio=2)
+    def missing_client_hello(self):
+        raise self.MISSING_CH()
+
+    @ATMT.state(final=True)
+    def MISSING_CH(self):
+        print "Missing TLS Client Hello message"
+
+    @ATMT.condition(HANDLE_CH, prio=2)
+    def should_REPLY_TO_CH(self):
+        """
+        XXX Several enhancements needed here.
+
+        Selecting a cipher suite should be no trouble as we already caught the
+        None case previously. However, regarding the protocol version, we
+        might want to try resending a ClientHello when the advertised
+        version is not deemed satisfying.
+
+        Then, the sending of ServerHello, Certificate, ServerKeyExchange and
+        ServerHelloDone should be split into multiple states, in order for the
+        user to overload only the ones he's interested in.
+
+        Also, we do not manage extensions at all.
+        """
+        if isinstance(self.mykey, PrivKeyRSA):
+            kx = "RSA"
+        elif isinstance(self.mykey, PrivKeyECDSA):
+            kx = "ECDSA"
+        usable_suites = get_usable_ciphersuites(self.cur_pkt.ciphers, kx)
+        c = usable_suites[0]
+        if self.preferred_ciphersuite in usable_suites:
+            c = self.preferred_ciphersuite
+
+        comp = 0
+        if self.cur_pkt.comp and 1 in self.cur_pkt.comp:
+            comp = 1
+
+        self.cur_session.advertised_tls_version = self.cur_pkt.version
+        self.cur_session.tls_version = self.cur_pkt.version
+        #XXX there should be some checks on this version from the ClientHello
+        v = self.cur_session.tls_version
+        print "\nVersion: " + _tls_version[v]
+        print "Cipher suite: " + _tls_cipher_suites[c]
+
+        self.cur_pkt = TLS(tls_session=self.cur_session, msg=[])
+
+        p = TLSServerHello(cipher=c, comp=[comp])
+        self.cur_pkt.msg.append(p)
+
+        p = TLSCertificate(certs=self.cur_session.server_certs)
+        self.cur_pkt.msg.append(p)
+
+        if not _tls_cipher_suites_cls[c].kx_alg.no_ske:
+            p = TLSServerKeyExchange()
+            self.cur_pkt.msg.append(p)
+
+        p = TLSServerHelloDone()
+        self.cur_pkt.msg.append(p)
+
+        self.socket.send(str(self.cur_pkt))
+        self.cur_pkt = None
+        raise self.SENT_SH()
+
+    @ATMT.state()
+    def SENT_SH(self):
+        pass
+
+    @ATMT.condition(SENT_SH, prio=1)
+    def should_HANDLE_CKE(self):
+        self.get_next_msg()
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSClientKeyExchange)):
+            return
+        self.cur_pkt = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+        raise self.HANDLE_CKE()
+
+    @ATMT.state()
+    def HANDLE_CKE(self):
+        pass
+
+    @ATMT.condition(SENT_SH, prio=2)
+    def should_HANDLE_ALERT_INSTEAD_OF_CKE(self):
+        self.get_next_msg()
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSAlert)):
+            return
+        self.cur_pkt = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+        raise self.HANDLE_ALERT_INSTEAD_OF_CKE()
+
+    @ATMT.state()
+    def HANDLE_ALERT_INSTEAD_OF_CKE(self):
+        print "Received Alert message instead of CKE"
+
+    @ATMT.condition(SENT_SH, prio=3)
+    def should_HANDLE_MISSING_CKE(self):
+        raise self.HANDLE_MISSING_CKE()
+
+    @ATMT.state()
+    def HANDLE_MISSING_CKE(self):
+        print "Missing CKE in client's reply"
+
+
+    @ATMT.condition(HANDLE_CKE, prio=1)
+    def should_HANDLE_CCS(self):
+        self.get_next_msg()
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSChangeCipherSpec)):
+            return
+        self.cur_pkt = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+        raise self.HANDLE_CCS()
+
+    @ATMT.state()
+    def HANDLE_CCS(self):
+        pass
+
+    @ATMT.condition(HANDLE_CKE, prio=2)
+    def should_HANDLE_ALERT_INSTEAD_OF_CCS(self):
+        self.get_next_msg()
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSAlert)):
+            return
+        self.cur_pkt = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+
+        raise self.HANDLE_ALERT_INSTEAD_OF_CCS()
+
+    @ATMT.state()
+    def HANDLE_ALERT_INSTEAD_OF_CCS(self):
+        print "Received Alert message instead of CCS"
+
+    @ATMT.condition(HANDLE_CKE, prio=3)
+    def should_HANDLE_MISSING_CCS(self):
+        raise self.HANDLE_MISSING_CCS()
+
+    @ATMT.state()
+    def HANDLE_MISSING_CCS(self):
+        print "Missing CCS in client's reply"
+
+    @ATMT.condition(HANDLE_CCS, prio=1)
+    def should_HANDLE_Finished(self):
+        self.get_next_msg()
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSFinished)):
+            return
+        self.cur_pkt = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+        raise self.HANDLE_FINISHED()
+
+    @ATMT.state()
+    def HANDLE_FINISHED(self):
+        pass
+
+    @ATMT.condition(HANDLE_CCS, prio=2)
+    def should_HANDLE_ALERT_INSTEAD_OF_Finished(self):
+        self.get_next_msg()
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSAlert)):
+            return
+        self.cur_pkt = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+        raise self.HANDLE_ALERT_INSTEAD_OF_FINISHED()
+
+    @ATMT.state()
+    def HANDLE_ALERT_INSTEAD_OF_FINISHED(self):
+        print "Received Alert message instead of Finished"
+
+    @ATMT.condition(HANDLE_CCS, prio=3)
+    def should_HANDLE_MISSING_FINISHED(self):
+        raise self.HANDLE_MISSING_FINISHED()
+
+    @ATMT.state()
+    def HANDLE_MISSING_FINISHED(self):
+        print "Missing Finished in client's reply"
+
+    @ATMT.condition(HANDLE_FINISHED, prio=1)
+    def should_SEND_CCS(self):
+        ccs = TLSChangeCipherSpec()
+        self.cur_pkt = TLS(type=20, msg=[ccs], tls_session=self.cur_session)
+        self.socket.send(str(self.cur_pkt))
+        self.cur_pkt = None
+        raise self.SEND_CCS()
+
+    @ATMT.state()
+    def SEND_CCS(self):
+        pass
+
+    @ATMT.condition(SEND_CCS, prio=2)
+    def should_SEND_FINISHED(self):
+        p = TLSFinished()
+        self.cur_pkt = TLS(tls_session=self.cur_session, msg=[p])
+        self.socket.send(str(self.cur_pkt))
+        self.cur_pkt = None
+        raise self.FINISHED_SENT()
+
+    @ATMT.state()
+    def FINISHED_SENT(self):
+        pass
+
+    @ATMT.condition(FINISHED_SENT, prio=0)
+    def should_HANDLE_NO_CLIENT(self):
+        self.get_next_msg()
+        if self.msg_list:
+            return
+        print "Client left. Closing connection..."
+        raise self.FINAL()
+
+    @ATMT.condition(FINISHED_SENT, prio=1)
+    def should_HANDLE_ALERT_FROM_FINISHED(self):
+        self.get_next_msg()
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSAlert)):
+            return
+        raise self.HANDLE_ALERT_FROM_FINISHED_SENT()
+
+    @ATMT.state()
+    def HANDLE_ALERT_FROM_FINISHED_SENT(self):
+        self.cur_pkt = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+        print "Received Alert Message after sending Finished"
+        print "Closing connection"
+        #XXX no support for new connections, for now
+        raise self.FINAL()
+
+    @ATMT.condition(FINISHED_SENT, prio=2)
+    def should_WAIT_DATA(self):
+        self.get_next_msg()
+        if self.msg_list:
+            return
+        # Client did not send anything, let's wait
+        raise self.FINISHED_SENT()
+
+    @ATMT.condition(FINISHED_SENT, prio=3)
+    def should_PROCESS_DATA(self):
+        self.get_next_msg()
+        if (not self.msg_list or
+            not isinstance(self.msg_list[0], TLSApplicationData)):
+            return
+        raise self.PROCESS_DATA()
+
+    @ATMT.state()
+    def PROCESS_DATA(self):
+        """
+        In the beginning, we return a small page with useful information.
+        Then, we act as an echo server.
+        """
+        self.cur_pkt = self.msg_list[0]
+        self.msg_list = self.msg_list[1:]
+
+        recv_data = self.cur_pkt.data
+        print "Received %s" % repr(recv_data)
+
+        if recv_data.startswith("GET / HTTP/1."):
+            header  = "HTTP/1.1 200 OK\r\n"
+            header += "Server: Scapy TLS Extension\r\n"
+            header += "Content-type: text/html\r\n"
+            header += "Content-length: %d\r\n\r\n"
+            s  = "Information on current TLS session:\n\n"
+            s += "Local end      : %s:%d\n" % (self.local_ip, self.local_port)
+            s += "Remote end     : %s:%d\n" % (self.remote_ip, self.remote_port)
+            v = self.cur_session.advertised_tls_version
+            v = "%s (0x%04x)" % (_tls_version[v], v)
+            s += "TLS version    : %s\n" % v
+            s += repr(self.cur_session.wcs)
+            body = "<html><body><pre>%s</pre></body></html>\r\n\r\n" % s
+            page = (header+body) % len(body)
+        else:
+            page = recv_data
+
+        p = Raw(load=page)
+        self.cur_pkt = TLS(type=23, msg=[p], tls_session=self.cur_session)
+        self.socket.send(str(self.cur_pkt))
+        raise self.FINISHED_SENT()
+
+    @ATMT.state(final=True)
+    def FINAL(self):
+        """
+        We might call shutdown, but unit tests with s_client fail with this.
+        #self.socket.shutdown(1)
+        """
+        self.socket.close()
+
diff --git a/scapy/layers/tls/basefields.py b/scapy/layers/tls/basefields.py
new file mode 100644
index 0000000000000000000000000000000000000000..cfa98d6e832cccfaf93e7197898fca4d0bc5b1fa
--- /dev/null
+++ b/scapy/layers/tls/basefields.py
@@ -0,0 +1,180 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+TLS base fields, used for record parsing/building. As several operations depend
+upon the TLS version or ciphersuite, the packet has to provide a TLS context.
+"""
+
+from scapy.fields import *
+
+
+_tls_type = { 20: "change_cipher_spec",
+	      21: "alert",
+	      22: "handshake",
+	      23: "application_data" }
+
+_tls_version = { 0x0200: "SSLv2",
+                 0x0300: "SSLv3",
+                 0x0301: "TLS 1.0",
+                 0x0302: "TLS 1.1",
+                 0x0303: "TLS 1.2" }
+
+
+class _TLSVersionField(ShortEnumField):
+    """
+    Behavior: if the user does not provide a value, we use the version provided
+    by tls_version parameter in packet's session, only if it is defined. In
+    that case, this is the version selected by the server. Otherwise, we use
+    the value provided by advertised_tls_version parameter in packet's session.
+    In that latter case, this is simply the version provided by the client.
+    """
+    def i2h(self, pkt, x):
+        if x is None:
+            if pkt.tls_session.tls_version:
+                return pkt.tls_session.tls_version
+            return pkt.tls_session.advertised_tls_version
+        return x
+
+    def i2m(self, pkt, x):
+        if x is None:
+            if pkt.tls_session.tls_version:
+                return pkt.tls_session.tls_version
+            return pkt.tls_session.advertised_tls_version
+        return x
+
+
+class _TLSClientVersionField(ShortEnumField):
+    """
+    Unlike _TLSVersionField, we use advertised_tls_version preferentially,
+    and then tls_version if there was none advertised.
+    """
+    def i2h(self, pkt, x):
+        if x is None:
+            if pkt.tls_session.advertised_tls_version:
+                return pkt.tls_session.advertised_tls_version
+            return pkt.tls_session.tls_version
+        return x
+
+    def i2m(self, pkt, x):
+        if x is None:
+            if pkt.tls_session.advertised_tls_version:
+                return pkt.tls_session.advertised_tls_version
+            return pkt.tls_session.tls_version
+        return x
+
+
+class _TLSLengthField(ShortField):
+    pass
+
+
+class _TLSIVField(StrField):
+    """
+    As stated in Section 6.2.3.2. RFC 4346, TLS 1.1 implements an explicit IV
+    mechanism. For that reason, the behavior of the field is dependent on the
+    TLS version found in the packet if available or otherwise (on build, if
+    not overloaded, it is provided by the session). The size of the IV and
+    its value are obviously provided by the session. As a side note, for the
+    first packets exchanged by peers, NULL being the default enc alg, it is
+    empty (except if forced to a specific value). Also note that the field is
+    kept empty (unless forced to a specific value) when the cipher is a stream
+    cipher (and NULL is considered a stream cipher).
+    """
+    def i2len(self, pkt, i):
+        if i is not None:
+            return len(i)
+        l = 0
+        cipher_type = pkt.tls_session.rcs.cipher.type
+        if cipher_type == "block":
+            if pkt.tls_session.tls_version >= 0x0302:
+                l = pkt.tls_session.rcs.cipher.block_size
+        elif cipher_type == "aead":
+            l = pkt.tls_session.rcs.cipher.nonce_explicit_len
+        return l
+
+    def i2m(self, pkt, x):
+        return x or ""
+
+    def addfield(self, pkt, s, val):
+        return s + self.i2m(pkt, val)
+
+    def getfield(self, pkt, s):
+        l = 0
+        cipher_type = pkt.tls_session.rcs.cipher.type
+        if cipher_type == "block":
+            if pkt.tls_session.tls_version >= 0x0302:
+                l = pkt.tls_session.rcs.cipher.block_size
+        elif cipher_type == "aead":
+            l = pkt.tls_session.rcs.cipher.nonce_explicit_len
+        return s[l:], self.m2i(pkt, s[:l])
+
+    def i2repr(self, pkt, x):
+        return repr(self.i2m(pkt, x))
+
+
+class _TLSMACField(StrField):
+    def i2len(self, pkt, i):
+        if i is not None:
+            return len(i)
+        return pkt.tls_session.wcs.mac_len
+
+    def i2m(self, pkt, x):
+        if x is None:
+            return ""
+        return x
+
+    def addfield(self, pkt, s, val):
+        # We add nothing here. This is done in .post_build() if needed.
+        return s
+
+    def getfield(self, pkt, s):
+        l = pkt.tls_session.rcs.mac_len
+        return s[l:], self.m2i(pkt, s[:l])
+
+    def i2repr(self, pkt, x):
+        #XXX Provide status when dissection has been performed successfully?
+        return repr(self.i2m(pkt, x))
+
+
+class _TLSPadField(StrField):
+    def i2len(self, pkt, i):
+        if i is not None:
+            return len(i)
+        return 0
+
+    def i2m(self, pkt, x):
+        if x is None:
+            return ""
+        return x
+
+    def addfield(self, pkt, s, val):
+        # We add nothing here. This is done in .post_build() if needed.
+        return s
+
+    def getfield(self, pkt, s):
+        if pkt.tls_session.consider_read_padding():
+            # We get the length from the last byte of s which
+            # is either the first byte of padding or the padding
+            # length field itself is padding length is 0.
+            # This should work with SSLv3 and also TLS versions.
+            l = ord(s[-1])
+            return s[l:], self.m2i(pkt, s[:l])
+        return s, None
+
+    def i2repr(self, pkt, x):
+        #XXX Provide status when dissection has been performed successfully?
+        return repr(self.i2m(pkt, x))
+
+
+class _TLSPadLenField(ByteField):
+    def addfield(self, pkt, s, val):
+        # We add nothing here. This is done in .post_build() if needed.
+        return s
+
+    def getfield(self, pkt, s):
+        if pkt.tls_session.consider_read_padding():
+            return ByteField.getfield(self, pkt, s)
+        return s, None
+
diff --git a/scapy/layers/tls/cert.py b/scapy/layers/tls/cert.py
index 8d81097e0668b2d7938dfb7e5816061966d65b41..8f816267a8d938e4612f3cafdde842d600f4d2e5 100644
--- a/scapy/layers/tls/cert.py
+++ b/scapy/layers/tls/cert.py
@@ -7,49 +7,47 @@
 """
 High-level methods for PKI objects (X.509 certificates, CRLs, asymmetric keys).
 Supports both RSA and ECDSA objects.
+
+The classes below are wrappers for the ASN.1 objects defined in x509.py.
+By collecting their attributes, we bypass the ASN.1 structure, hence
+there is no direct method for exporting a new full DER-encoded version
+of a Cert instance after its serial has been modified (for example).
+If you need to modify an import, just use the corresponding ASN1_Packet.
+
+For instance, here is what you could do in order to modify the serial of
+'cert' and then resign it with whatever 'key':
+    f = open('cert.der')
+    c = X509_Cert(f.read())
+    c.tbsCertificate.serialNumber = 0x4B1D
+    k = PrivKey('key.pem')
+    new_x509_cert = k.resignCert(c)
+No need for obnoxious openssl tweaking anymore. :)
 """
 
-## This module relies on python-crypto and python-ecdsa.
-##
-## The classes below are wrappers for the ASN.1 objects defined in x509.py.
-## By collecting their attributes, we bypass the ASN.1 structure, hence
-## there is no direct method for exporting a new full DER-encoded version
-## of a Cert instance after its serial has been modified (for example).
-## If you need to modify an import, just use the corresponding ASN1_Packet.
-##
-## For instance, here is what you could do in order to modify the serial of
-## 'cert' and then resign it with whatever 'key':
-##     f = open('cert.der')
-##     c = X509_Cert(f.read())
-##     c.tbsCertificate.serialNumber = 0x4B1D
-##     k = PrivKey('key.pem')
-##     new_x509_cert = k.resignCert(c)
-## No need for obnoxious openssl tweaking anymore. :)
-
-import base64, os, time
-
-import ecdsa
+import base64
+import os
+import time
 
 from scapy.config import conf, crypto_validator
 if conf.crypto_valid:
     from cryptography.hazmat.backends import default_backend
+    from cryptography.hazmat.primitives import serialization
     from cryptography.hazmat.primitives.asymmetric import rsa
 else:
-    default_backend = rsa = None
-
-from scapy.layers.tls.crypto.curves import import_curve
-from scapy.layers.tls.crypto.pkcs1 import pkcs_os2ip, pkcs_i2osp, mapHashFunc
-from scapy.layers.tls.crypto.pkcs1 import _EncryptAndVerifyRSA
-from scapy.layers.tls.crypto.pkcs1 import _DecryptAndSignRSA
+    default_backend = rsa = serialization = None
 
+from scapy.error import warning
+from scapy.utils import binrepr
 from scapy.asn1.asn1 import ASN1_BIT_STRING
 from scapy.asn1.mib import hash_by_oid
-from scapy.layers.x509 import X509_SubjectPublicKeyInfo
-from scapy.layers.x509 import RSAPublicKey, RSAPrivateKey
-from scapy.layers.x509 import ECDSAPublicKey, ECDSAPrivateKey
-from scapy.layers.x509 import RSAPrivateKey_OpenSSL, ECDSAPrivateKey_OpenSSL
-from scapy.layers.x509 import X509_Cert, X509_CRL
-from scapy.utils import binrepr
+from scapy.layers.x509 import (X509_SubjectPublicKeyInfo,
+                               RSAPublicKey, RSAPrivateKey,
+                               ECDSAPublicKey, ECDSAPrivateKey,
+                               RSAPrivateKey_OpenSSL, ECDSAPrivateKey_OpenSSL,
+                               X509_Cert, X509_CRL)
+from scapy.layers.tls.crypto.pkcs1 import (pkcs_os2ip, pkcs_i2osp, mapHashFunc,
+                                           _EncryptAndVerifyRSA,
+                                           _DecryptAndSignRSA)
 
 # Maximum allowed size in bytes for a certificate file, to avoid
 # loading huge file when importing a cert
@@ -62,10 +60,10 @@ MAX_CRL_SIZE = 10*1024*1024   # some are that big
 # Some helpers
 #####################################################################
 
+@conf.commands.register
 def der2pem(der_string, obj="UNKNOWN"):
-    """
-    Encode a byte string in PEM format. Header advertizes <obj> type.
-    """
+    """Convert DER octet string to PEM format (with optional header)"""
+    # Encode a byte string in PEM format. Header advertizes <obj> type.
     pem_string = "-----BEGIN %s-----\n" % obj
     base64_string = base64.b64encode(der_string)
     chunks = [base64_string[i:i+64] for i in range(0, len(base64_string), 64)]
@@ -73,10 +71,10 @@ def der2pem(der_string, obj="UNKNOWN"):
     pem_string += "\n-----END %s-----\n" % obj
     return pem_string
 
+@conf.commands.register
 def pem2der(pem_string):
-    """
-    Encode every line between the first '-----\n' and the 2nd-to-last '-----'.
-    """
+    """Convert PEM string to DER format"""
+    # Encode all lines between the first '-----\n' and the 2nd-to-last '-----'.
     pem_string = pem_string.replace("\r", "")
     first_idx = pem_string.find("-----\n") + 6
     if pem_string.find("-----BEGIN", first_idx) != -1:
@@ -107,6 +105,7 @@ class _PKIObj(object):
     def __init__(self, frmt, der, pem):
         # Note that changing attributes of the _PKIObj does not update these
         # values (e.g. modifying k.modulus does not change k.der).
+        #XXX use __setattr__ for this
         self.frmt = frmt
         self.der = der
         self.pem = pem
@@ -174,18 +173,25 @@ class _PubKeyFactory(_PKIObjMaker):
     """
     Metaclass for PubKey creation.
     It casts the appropriate class on the fly, then fills in
-    the appropriate attributes with updateWith() submethod.
+    the appropriate attributes with import_from_asn1pkt() submethod.
     """
-    def __call__(cls, key_path):
+    def __call__(cls, key_path=None):
+
+        if key_path is None:
+            obj = type.__call__(cls)
+            if cls is PubKey:
+                cls = PubKeyRSA
+            obj.__class__ = cls
+            obj.frmt = "original"
+            obj.fill_and_store()
+            return obj
 
-        # First, we deal with the exceptional RSA KEA call.
+        # This deals with the rare RSA 'kx export' call.
         if type(key_path) is tuple:
-            e, m, mLen = key_path
             obj = type.__call__(cls)
+            obj.__class__ = PubKeyRSA
             obj.frmt = "tuple"
-            obj.modulus = m
-            obj.modulusLen = mLen
-            obj.pubExp = e
+            obj.import_from_tuple(key_path)
             return obj
 
         # Now for the usual calls, key_path may be the path to either:
@@ -198,10 +204,13 @@ class _PubKeyFactory(_PKIObjMaker):
             pubkey = spki.subjectPublicKey
             if isinstance(pubkey, RSAPublicKey):
                 obj.__class__ = PubKeyRSA
-                obj.updateWith(pubkey)
+                obj.import_from_asn1pkt(pubkey)
             elif isinstance(pubkey, ECDSAPublicKey):
                 obj.__class__ = PubKeyECDSA
-                obj.updateWith(spki)
+                try:
+                    obj.import_from_der(obj.der)
+                except ImportError:
+                    pass
             else:
                 raise
             marker = "PUBLIC KEY"
@@ -209,7 +218,7 @@ class _PubKeyFactory(_PKIObjMaker):
             try:
                 pubkey = RSAPublicKey(obj.der)
                 obj.__class__ = PubKeyRSA
-                obj.updateWith(pubkey)
+                obj.import_from_asn1pkt(pubkey)
                 marker = "RSA PUBLIC KEY"
             except:
                 # We cannot import an ECDSA public key without curve knowledge
@@ -228,74 +237,96 @@ class PubKey(object):
     __metaclass__ = _PubKeyFactory
 
     def verifyCert(self, cert):
-        """
-        Verifies either a Cert or an X509_Cert.
-        """
+        """ Verifies either a Cert or an X509_Cert. """
         tbsCert = cert.tbsCertificate
         sigAlg = tbsCert.signature
         h = hash_by_oid[sigAlg.algorithm.val]
         sigVal = str(cert.signatureValue)
-        return self.verify(str(tbsCert), sigVal, h=h,
-                           t='pkcs',
-                           sigdecode=ecdsa.util.sigdecode_der)
+        return self.verify(str(tbsCert), sigVal, h=h, t='pkcs')
 
 
-class PubKeyRSA(_PKIObj, PubKey, _EncryptAndVerifyRSA):
+class PubKeyRSA(PubKey, _EncryptAndVerifyRSA):
     """
     Wrapper for RSA keys based on _EncryptAndVerifyRSA from crypto/pkcs1.py
     Use the 'key' attribute to access original object.
     """
     @crypto_validator
-    def updateWith(self, pubkey):
-        self.modulus    = pubkey.modulus.val
-        self.modulusLen = len(binrepr(pubkey.modulus.val))
-        self.pubExp     = pubkey.publicExponent.val
-        self.key = rsa.RSAPublicNumbers(
-            n=self.modulus,
-            e=self.pubExp
-        ).public_key(default_backend())
+    def fill_and_store(self, modulus=None, modulusLen=None, pubExp=None):
+        pubExp = pubExp or 65537
+        if modulus is None:
+            real_modulusLen = modulusLen or 2048
+            private_key = rsa.generate_private_key(public_exponent=pubExp,
+                                                   key_size=real_modulusLen,
+                                                   backend=default_backend())
+            self.pubkey = private_key.public_key()
+        else:
+            real_modulusLen = len(binrepr(modulus))
+            if real_modulusLen != modulusLen:
+                warning("modulus and modulusLen do not match!")
+            pubNum = rsa.RSAPublicNumbers(n=modulus, e=pubExp)
+            self.pubkey = pubNum.public_key(default_backend())
+        #XXX lines below should be removed once pkcs1.py is cleaned of legacy
+        pubNum = self.pubkey.public_numbers()
+        self._modulusLen = real_modulusLen
+        self._modulus = pubNum.n
+        self._pubExp = pubNum.e
+
+    @crypto_validator
+    def import_from_tuple(self, tup):
+        # this is rarely used
+        e, m, mLen = tup
+        if isinstance(m, str):
+            m = pkcs_os2ip(m)
+        if isinstance(e, str):
+            e = pkcs_os2ip(e)
+        self.fill_and_store(modulus=m, pubExp=e)
+        self.pem = self.pubkey.public_bytes(
+                        encoding=serialization.Encoding.PEM,
+                        format=serialization.PublicFormat.SubjectPublicKeyInfo)
+        self.der = pem2der(self.pem)
+
+    def import_from_asn1pkt(self, pubkey):
+        modulus    = pubkey.modulus.val
+        pubExp     = pubkey.publicExponent.val
+        self.fill_and_store(modulus=modulus, pubExp=pubExp)
+
     def encrypt(self, msg, t=None, h=None, mgf=None, L=None):
         # no ECDSA encryption support, hence no ECDSA specific keywords here
         return _EncryptAndVerifyRSA.encrypt(self, msg, t=t, h=h, mgf=mgf, L=L)
+
     def verify(self, msg, sig, h=None,
-               t=None, mgf=None, sLen=None,
-               sigdecode=None):
+               t=None, mgf=None, sLen=None):
         return _EncryptAndVerifyRSA.verify(self, msg, sig, h=h,
                                            t=t, mgf=mgf, sLen=sLen)
 
-
-class PubKeyECDSA(_PKIObj, PubKey):
+class PubKeyECDSA(PubKey):
     """
-    Wrapper for ECDSA keys based on VerifyingKey from ecdsa library.
+    Wrapper for ECDSA keys based on the cryptography library.
     Use the 'key' attribute to access original object.
     """
-    def updateWith(self, spki):
-        # For now we use from_der() or from_string() methods,
-        # which do not offer support for compressed points.
-        #XXX Try using the from_public_point() method.
-        try:
-            self.key = ecdsa.VerifyingKey.from_der(str(spki))
-            # from_der() raises an exception on explicit curves
-        except:
-            s = spki.subjectPublicKey.val_readable[1:]
-            p = spki.signatureAlgorithm.parameters
-            c = import_curve(p.fieldID.prime.val,
-                             p.curve.a.val,
-                             p.curve.b.val,
-                             p.base.val,
-                             p.order.val)
-            self.key = ecdsa.VerifyingKey.from_string(s, c)
-    def encrypt(self, msg, t=None, h=None, mgf=None, L=None):
-        # python-ecdsa does not support encryption
+    @crypto_validator
+    def fill_and_store(self, curve=None):
+        curve = curve or ec.SECP256R1
+        private_key = ec.generate_private_key(curve(), default_backend())
+        self.pubkey = private_key.public_key()
+
+    @crypto_validator
+    def import_from_der(self, pubkey):
+        # XXX does the cryptography lib support explicit curves?
+        # check also for compressed points
+        self.pubkey = serialization.load_der_public_key(pubkey,
+                                                    backend=default_backend())
+
+    def encrypt(self, msg, h=None, **kwargs):
+        # cryptography lib does not support ECDSA encryption
         raise Exception("No ECDSA encryption support")
-    def verify(self, msg, sig, h=None,
-               t=None, mgf=None, sLen=None,
-               sigdecode=ecdsa.util.sigdecode_string):
-        try:
-            return self.key.verify(sig, msg, hashfunc=mapHashFunc(h),
-                                   sigdecode=sigdecode)
-        except ecdsa.keys.BadSignatureError:
-            return False
+
+    @crypto_validator
+    def verify(self, msg, sig, h=None, **kwargs):
+        # 'sig' should be a DER-encoded signature, as per RFC 3279
+        verifier = self.pubkey.verifier(sig, ec.ECDSA(mapHashFunc(h)))
+        verifier.update(msg)
+        return verifier.verify()
 
 
 ################
@@ -306,9 +337,9 @@ class _PrivKeyFactory(_PKIObjMaker):
     """
     Metaclass for PrivKey creation.
     It casts the appropriate class on the fly, then fills in
-    the appropriate attributes with updateWith() submethod.
+    the appropriate attributes with import_from_asn1pkt() submethod.
     """
-    def __call__(cls, key_path):
+    def __call__(cls, key_path=None):
         """
         key_path may be the path to either:
             _an RSAPrivateKey_OpenSSL (as generated by openssl);
@@ -316,6 +347,15 @@ class _PrivKeyFactory(_PKIObjMaker):
             _an RSAPrivateKey;
             _an ECDSAPrivateKey.
         """
+        if key_path is None:
+            obj = type.__call__(cls)
+            if cls is PrivKey:
+                cls = PrivKeyECDSA
+            obj.__class__ = cls
+            obj.frmt = "original"
+            obj.fill_and_store()
+            return obj
+
         obj = _PKIObjMaker.__call__(cls, key_path, MAX_KEY_SIZE)
         multiPEM = False
         try:
@@ -342,7 +382,10 @@ class _PrivKeyFactory(_PKIObjMaker):
                         marker = "EC PRIVATE KEY"
                     except:
                         raise Exception("Unable to import private key")
-        obj.updateWith(privkey)
+        try:
+            obj.import_from_asn1pkt(privkey)
+        except ImportError:
+            pass
 
         if obj.frmt == "DER":
             if multiPEM:
@@ -372,14 +415,11 @@ class PrivKey(object):
         to both PrivKeyRSA and PrivKeyECDSA, the sign() methods of the
         subclasses accept any argument, be it from the RSA or ECDSA world,
         and then they keep the ones they're interested in.
-        Here, t will be passed eventually to pkcs1._DecryptAndSignRSA.sign(),
-        while sigencode will be passed to ecdsa.keys.SigningKey.sign().
+        Here, t will be passed eventually to pkcs1._DecryptAndSignRSA.sign().
         """
         sigAlg = tbsCert.signature
         h = h or hash_by_oid[sigAlg.algorithm.val]
-        sigVal = self.sign(str(tbsCert), h=h,
-                           t='pkcs',
-                           sigencode=ecdsa.util.sigencode_der)
+        sigVal = self.sign(str(tbsCert), h=h, t='pkcs')
         c = X509_Cert()
         c.tbsCertificate = tbsCert
         c.signatureAlgorithm = sigAlg
@@ -387,63 +427,110 @@ class PrivKey(object):
         return c
 
     def resignCert(self, cert):
-        # works with both Cert and X509_Cert types
+        """ Rewrite the signature of either a Cert or an X509_Cert. """
         return self.signTBSCert(cert.tbsCertificate)
 
+    def verifyCert(self, cert):
+        """ Verifies either a Cert or an X509_Cert. """
+        tbsCert = cert.tbsCertificate
+        sigAlg = tbsCert.signature
+        h = hash_by_oid[sigAlg.algorithm.val]
+        sigVal = str(cert.signatureValue)
+        return self.verify(str(tbsCert), sigVal, h=h, t='pkcs')
+
 
-class PrivKeyRSA(_PKIObj, PrivKey, _EncryptAndVerifyRSA, _DecryptAndSignRSA):
+class PrivKeyRSA(PrivKey, _EncryptAndVerifyRSA, _DecryptAndSignRSA):
     """
     Wrapper for RSA keys based on _DecryptAndSignRSA from crypto/pkcs1.py
     Use the 'key' attribute to access original object.
     """
     @crypto_validator
-    def updateWith(self, privkey):
-        self.modulus     = privkey.modulus.val
-        self.modulusLen  = len(binrepr(privkey.modulus.val))
-        self.pubExp      = privkey.publicExponent.val
-        self.privExp     = privkey.privateExponent.val
-        self.prime1      = privkey.prime1.val
-        self.prime2      = privkey.prime2.val
-        self.exponent1   = privkey.exponent1.val
-        self.exponent2   = privkey.exponent2.val
-        self.coefficient = privkey.coefficient.val
-        self.key = rsa.RSAPrivateNumbers(
-            p=self.prime1, q=self.prime2, d=self.privExp, dmp1=self.exponent1,
-            dmq1=self.exponent2, iqmp=self.coefficient,
-            public_numbers=rsa.RSAPublicNumbers(n=self.modulus, e=self.pubExp),
-        ).private_key(default_backend())
+    def fill_and_store(self, modulus=None, modulusLen=None, pubExp=None,
+                             prime1=None, prime2=None, coefficient=None,
+                             exponent1=None, exponent2=None, privExp=None):
+        pubExp = pubExp or 65537
+        if None in [modulus, prime1, prime2, coefficient, privExp,
+                    exponent1, exponent2]:
+            # note that the library requires every parameter
+            # in order to call RSAPrivateNumbers(...)
+            # if one of these is missing, we generate a whole new key
+            real_modulusLen = modulusLen or 2048
+            self.key = rsa.generate_private_key(public_exponent=pubExp,
+                                                key_size=real_modulusLen,
+                                                backend=default_backend())
+            self.pubkey = self.key.public_key()
+        else:
+            real_modulusLen = len(binrepr(modulus))
+            if real_modulusLen != modulusLen:
+                warning("modulus and modulusLen do not match!")
+            pubNum = rsa.RSAPublicNumbers(n=modulus, e=pubExp)
+            privNum = rsa.RSAPrivateNumbers(p=prime1, q=prime2,
+                                            dmp1=exponent1, dmq1=exponent2,
+                                            iqmp=coefficient, d=privExp,
+                                            public_numbers=pubNum)
+            self.key = privNum.private_key(default_backend())
+            self.pubkey = self.key.public_key()
+        #XXX lines below should be removed once pkcs1.py is cleaned of legacy
+        pubNum = self.pubkey.public_numbers()
+        self._modulusLen = real_modulusLen
+        self._modulus = pubNum.n
+        self._pubExp = pubNum.e
+
+    def import_from_asn1pkt(self, privkey):
+        modulus     = privkey.modulus.val
+        pubExp      = privkey.publicExponent.val
+        privExp     = privkey.privateExponent.val
+        prime1      = privkey.prime1.val
+        prime2      = privkey.prime2.val
+        exponent1   = privkey.exponent1.val
+        exponent2   = privkey.exponent2.val
+        coefficient = privkey.coefficient.val
+        self.fill_and_store(modulus=modulus, pubExp=pubExp,
+                            privExp=privExp, prime1=prime1, prime2=prime2,
+                            exponent1=exponent1, exponent2=exponent2,
+                            coefficient=coefficient)
+
     def verify(self, msg, sig, h=None,
-               t=None, mgf=None, sLen=None,
-               sigdecode=None):
+               t=None, mgf=None, sLen=None):
         # Let's copy this from PubKeyRSA instead of adding another baseclass :)
         return _EncryptAndVerifyRSA.verify(self, msg, sig, h=h,
                                            t=t, mgf=mgf, sLen=sLen)
+
     def sign(self, data, h=None,
-             t=None, mgf=None, sLen=None,
-             k=None, entropy=None, sigencode=None):
+             t=None, mgf=None, sLen=None):
         return _DecryptAndSignRSA.sign(self, data, h=h,
                                        t=t, mgf=mgf, sLen=sLen)
 
 
-class PrivKeyECDSA(_PKIObj, PrivKey):
+class PrivKeyECDSA(PrivKey):
     """
     Wrapper for ECDSA keys based on SigningKey from ecdsa library.
     Use the 'key' attribute to access original object.
     """
-    def updateWith(self, privkey):
-        self.privKey = pkcs_os2ip(privkey.privateKey.val)
-        self.key = ecdsa.SigningKey.from_der(str(privkey))
-        self.vkey = self.key.get_verifying_key()
-    def verify(self, msg, sig, h=None,
-               t=None, mgf=None, sLen=None,
-               sigdecode=None):
-        return self.vkey.verify(sig, msg, hashfunc=mapHashFunc(h),
-                                sigdecode=sigdecode)
-    def sign(self, data, h=None,
-             t=None, mgf=None, sLen=None,
-             k=None, entropy=None, sigencode=ecdsa.util.sigencode_string):
-        return self.key.sign(data, hashfunc=mapHashFunc(h),
-                             k=k, entropy=entropy, sigencode=sigencode)
+    @crypto_validator
+    def fill_and_store(self, curve=None):
+        curve = curve or ec.SECP256R1
+        self.key = ec.generate_private_key(curve(), default_backend())
+        self.pubkey = self.key.public_key()
+
+    @crypto_validator
+    def import_from_asn1pkt(self, privkey):
+        self.key = serialization.load_der_private_key(str(privkey), None,
+                                                  backend=default_backend())
+        self.pubkey = self.key.public_key()
+
+    @crypto_validator
+    def verify(self, msg, sig, h=None, **kwargs):
+        # 'sig' should be a DER-encoded signature, as per RFC 3279
+        verifier = self.pubkey.verifier(sig, ec.ECDSA(mapHashFunc(h)))
+        verifier.update(msg)
+        return verifier.verify()
+
+    @crypto_validator
+    def sign(self, data, h=None, **kwargs):
+        signer = self.key.signer(ec.ECDSA(mapHashFunc(h)))
+        signer.update(data)
+        return signer.finalize()
 
 
 ################
@@ -463,18 +550,18 @@ class _CertMaker(_PKIObjMaker):
             cert = X509_Cert(obj.der)
         except:
             raise Exception("Unable to import certificate")
-        obj.updateWith(cert)
+        obj.import_from_asn1pkt(cert)
         return obj
 
 
-class Cert(_PKIObj):
+class Cert(object):
     """
     Wrapper for the X509_Cert from layers/x509.py.
     Use the 'x509Cert' attribute to access original object.
     """
     __metaclass__ = _CertMaker
 
-    def updateWith(self, cert):
+    def import_from_asn1pkt(self, cert):
         error_msg = "Unable to import certificate"
 
         self.x509Cert = cert
@@ -558,11 +645,9 @@ class Cert(_PKIObj):
         return self.pubKey.encrypt(msg, t=t, h=h, mgf=mgf, L=L)
 
     def verify(self, msg, sig, h=None,
-               t=None, mgf=None, sLen=None,
-               sigdecode=None):
+               t=None, mgf=None, sLen=None):
         return self.pubKey.verify(msg, sig, h=h,
-                                  t=t, mgf=mgf, sLen=sLen,
-                                  sigdecode=sigdecode)
+                                  t=t, mgf=mgf, sLen=sLen)
 
     def remainingDays(self, now=None):
         """
@@ -593,7 +678,7 @@ class Cert(_PKIObj):
                 else:
                     now = time.strptime(now, '%b %d %H:%M:%S %Y %Z')
             except:
-                print "Bad time string provided, will use localtime() instead."
+                warning("Bad time string provided, will use localtime() instead.")
                 now = time.localtime()
 
         now = time.mktime(now)
@@ -665,18 +750,18 @@ class _CRLMaker(_PKIObjMaker):
             crl = X509_CRL(obj.der)
         except:
             raise Exception("Unable to import CRL")
-        obj.updateWith(crl)
+        obj.import_from_asn1pkt(crl)
         return obj
 
 
-class CRL(_PKIObj):
+class CRL(object):
     """
     Wrapper for the X509_CRL from layers/x509.py.
     Use the 'x509CRL' attribute to access original object.
     """
     __metaclass__ = _CRLMaker
 
-    def updateWith(self, crl):
+    def import_from_asn1pkt(self, crl):
         error_msg = "Unable to import CRL"
 
         self.x509CRL = crl
diff --git a/scapy/layers/tls/crypto/__init__.py b/scapy/layers/tls/crypto/__init__.py
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..12affb4e0d1d1a5a80cf589d0c5cff1e2c94cb39 100644
--- a/scapy/layers/tls/crypto/__init__.py
+++ b/scapy/layers/tls/crypto/__init__.py
@@ -0,0 +1,9 @@
+# This file is part of Scapy
+# Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+#                     2015, 2016 Maxence Tury
+# This program is published under a GPLv2 license
+
+"""
+Cryptographic capabilities for TLS.
+"""
+
diff --git a/scapy/layers/tls/crypto/all.py b/scapy/layers/tls/crypto/all.py
new file mode 100644
index 0000000000000000000000000000000000000000..e8192a55dcec9a67aa4c0b027f6fa16a5b40c2c7
--- /dev/null
+++ b/scapy/layers/tls/crypto/all.py
@@ -0,0 +1,15 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+Aggregate some TLS crypto objects.
+"""
+
+# XXX This line should be removed once standard FFDH groups have been
+# registered in the cryptography library.
+from scapy.layers.tls.crypto.ffdh import *
+
+from scapy.layers.tls.crypto.suites import *
+
diff --git a/scapy/layers/tls/crypto/cipher_aead.py b/scapy/layers/tls/crypto/cipher_aead.py
new file mode 100644
index 0000000000000000000000000000000000000000..3b9d84a095bce3b6b1a25cc5d10af8f1e0d78ee6
--- /dev/null
+++ b/scapy/layers/tls/crypto/cipher_aead.py
@@ -0,0 +1,194 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+Authenticated Encryption with Associated Data ciphers.
+
+RFC 5288 introduces new ciphersuites for TLS 1.2 which are based on AES in
+Galois/Counter Mode (GCM). RFC 6655 in turn introduces AES_CCM ciphersuites.
+The related AEAD algorithms are defined in RFC 5116.
+
+For now the cryptography library only supports GCM mode.
+Their interface might (and should) be changed in the future.
+"""
+
+import struct
+
+from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
+from cryptography.hazmat.backends import default_backend
+from cryptography.exceptions import InvalidTag
+
+from scapy.layers.tls.crypto.pkcs1 import pkcs_i2osp, pkcs_os2ip
+from scapy.layers.tls.crypto.ciphers import CipherError
+
+
+tls_aead_cipher_algs = {}
+
+class _AEADCipherMetaclass(type):
+    """
+    Cipher classes are automatically registered through this metaclass.
+    Furthermore, their name attribute is extracted from their class name.
+    """
+    def __new__(cls, ciph_name, bases, dct):
+        if ciph_name != "_AEADCipher":
+            dct["name"] = ciph_name[7:]     # remove leading "Cipher_"
+        the_class = super(_AEADCipherMetaclass, cls).__new__(cls, ciph_name,
+                                                             bases, dct)
+        if ciph_name != "_AEADCipher":
+            tls_aead_cipher_algs[ciph_name[7:]] = the_class
+        return the_class
+
+
+class AEADTagError(Exception):
+    """
+    Raised when MAC verification fails. Hopefully you can access to the
+    deciphered (but unathenticated) plaintext as e.args.
+    """
+    pass
+
+class _AEADCipher(object):
+    __metaclass__ = _AEADCipherMetaclass
+    type = "aead"
+
+    def __init__(self, key=None, salt=None, nonce_explicit=None):
+        """
+        'key' and 'salt' are to be provided as strings, whereas the internal
+        'nonce_explicit' is an integer (it is simpler for incrementation).
+        """
+        self.ready = {"key":True, "salt":True, "nonce_explicit":True}
+        if key is None:
+            self.ready["key"] = False
+            key = "\0" * self.key_len
+        if salt is None:
+            self.ready["salt"] = False
+            salt = "\0" * self.salt_len
+        if nonce_explicit is None:
+            self.ready["nonce_explicit"] = False
+            nonce_explicit = 0
+
+        if type(nonce_explicit) is str:
+            nonce_explicit = pkcs_os2ip(nonce_explicit)
+
+        # we use super() in order to avoid any deadlock with __setattr__
+        super(_AEADCipher, self).__setattr__("key", key)
+        super(_AEADCipher, self).__setattr__("salt", salt)
+        super(_AEADCipher, self).__setattr__("nonce_explicit", nonce_explicit)
+
+        iv = salt + pkcs_i2osp(nonce_explicit, self.nonce_explicit_len)
+        self._cipher = Cipher(self.pc_cls(key),
+                              self.pc_cls_mode(iv),
+                              backend=default_backend())
+
+    def __setattr__(self, name, val):
+        if name == "key":
+            if self._cipher is not None:
+                self._cipher.algorithm.key = val
+            self.ready["key"] = True
+        elif name == "salt":
+            iv = val + pkcs_i2osp(self.nonce_explicit, self.nonce_explicit_len)
+            if self._cipher is not None:
+                self._cipher.mode._initialization_vector = iv
+            self.ready["salt"] = True
+        elif name == "nonce_explicit":
+            if type(val) is str:
+                val = pkcs_os2ip(val)
+            iv = self.salt + pkcs_i2osp(val, self.nonce_explicit_len)
+            if self._cipher is not None:
+                self._cipher.mode._initialization_vector = iv
+            self.ready["nonce_explicit"] = True
+        super(_AEADCipher, self).__setattr__(name, val)
+
+    def _update_nonce(self):
+        """
+        Increment the explicit nonce while avoiding any overflow.
+        """
+        ne = self.nonce_explicit + 1
+        self.nonce_explicit = ne % 2**(self.nonce_explicit_len*8)
+
+    def auth_encrypt(self, P, A):
+        """
+        Encrypt the data, prepend the explicit part of the nonce,
+        and append the computed authentication code.
+        Additional data may be authenticated without encryption (as A).
+
+        Note that the cipher's authentication tag must be None when encrypting.
+        """
+        if False in self.ready.itervalues():
+            raise CipherError, (P, A)
+        self._cipher.mode._tag = None
+        encryptor = self._cipher.encryptor()
+        encryptor.authenticate_additional_data(A)
+        res = encryptor.update(P) + encryptor.finalize()
+        res += encryptor.tag
+
+        nonce_explicit = pkcs_i2osp(self.nonce_explicit,
+                                    self.nonce_explicit_len)
+        self._update_nonce()
+        return nonce_explicit + res
+
+    def auth_decrypt(self, A, C, add_length=True):
+        """
+        Decrypt the data and verify the authentication code (in this order).
+        When additional data was authenticated, it has to be passed (as A).
+        If the verification fails, an AEADTagError is raised. It is the user's
+        responsibility to catch it if deemed useful. If we lack the key, we
+        raise a CipherError which contains the encrypted input.
+
+        Note that we add the TLSCiphertext length to A although we're supposed
+        to add the TLSCompressed length. Fortunately, they are the same,
+        but the specifications actually messed up here. :'(
+
+        The 'add_length' switch should always be True for TLS, but we provide
+        it anyway (mostly for test cases, hum).
+        """
+        nonce_explicit_str, C, mac = (C[:self.nonce_explicit_len],
+                                      C[self.nonce_explicit_len:-self.tag_len],
+                                      C[-self.tag_len:])
+
+        if False in self.ready.itervalues():
+            raise CipherError, (nonce_explicit_str, C, mac)
+
+        self.nonce_explicit = pkcs_os2ip(nonce_explicit_str)
+        self._cipher.mode._tag = mac
+
+        decryptor = self._cipher.decryptor()
+        if add_length:
+            A += struct.pack("!H", len(C))
+        decryptor.authenticate_additional_data(A)
+
+        P = decryptor.update(C)
+        try:
+            decryptor.finalize()
+        except InvalidTag:
+            raise AEADTagError, (nonce_explicit_str, P, mac)
+        return nonce_explicit_str, P, mac
+
+
+class Cipher_AES_128_GCM(_AEADCipher):
+    pc_cls = algorithms.AES
+    pc_cls_mode = modes.GCM
+    block_size = 16
+    key_len = 16
+    salt_len = 4
+    nonce_explicit_len = 8
+    tag_len = 16
+
+class Cipher_AES_256_GCM(Cipher_AES_128_GCM):
+    key_len = 32
+
+
+# no support for now in the cryptography library
+#class Cipher_AES_128_CCM(_AEADCipher):
+#    pc_cls_mode = modes.CCM
+#
+#class Cipher_AES_256_CCM(Cipher_AES_128_CCM):
+#    key_len = 32
+#
+#class Cipher_AES_128_CCM_8(Cipher_AES_128_CCM):
+#    tag_len = 8
+#
+#class Cipher_AES_256_CCM_8(Cipher_AES_128_CCM_8):
+#    key_len = 32
+
diff --git a/scapy/layers/tls/crypto/cipher_block.py b/scapy/layers/tls/crypto/cipher_block.py
new file mode 100644
index 0000000000000000000000000000000000000000..de750438863f0adb8f3f4f8129c20a9a70351fa9
--- /dev/null
+++ b/scapy/layers/tls/crypto/cipher_block.py
@@ -0,0 +1,157 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+Block ciphers.
+"""
+
+from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
+from cryptography.hazmat.backends import default_backend
+
+from scapy.utils import strxor
+from scapy.layers.tls.crypto.ciphers import CipherError
+
+
+tls_block_cipher_algs = {}
+
+class _BlockCipherMetaclass(type):
+    """
+    Cipher classes are automatically registered through this metaclass.
+    Furthermore, their name attribute is extracted from their class name.
+    """
+    def __new__(cls, ciph_name, bases, dct):
+        if ciph_name != "_BlockCipher":
+            dct["name"] = ciph_name[7:]     # remove leading "Cipher_"
+        the_class = super(_BlockCipherMetaclass, cls).__new__(cls, ciph_name,
+                                                              bases, dct)
+        if ciph_name != "_BlockCipher":
+            tls_block_cipher_algs[ciph_name[7:]] = the_class
+        return the_class
+
+
+class _BlockCipher(object):
+    __metaclass__ = _BlockCipherMetaclass
+    type = "block"
+
+    def __init__(self, key=None, iv=None):
+        self.ready = {"key":True, "iv":True}
+        if key is None:
+            self.ready["key"] = False
+            key = "\0" * self.key_len
+        if iv is None or iv == "":
+            self.ready["iv"] = False
+            iv = "\0" * self.block_size
+
+        # we use super() in order to avoid any deadlock with __setattr__
+        super(_BlockCipher, self).__setattr__("key", key)
+        super(_BlockCipher, self).__setattr__("iv", iv)
+
+        self._cipher = Cipher(self.pc_cls(key),
+                              self.pc_cls_mode(iv),
+                              backend=default_backend())
+
+    def __setattr__(self, name, val):
+        if name == "key":
+            if self._cipher is not None:
+                self._cipher.algorithm.key = val
+            self.ready["key"] = True
+        elif name == "iv":
+            if self._cipher is not None:
+                self._cipher.mode._initialization_vector = val
+            self.ready["iv"] = True
+        super(_BlockCipher, self).__setattr__(name, val)
+
+
+    def encrypt(self, data):
+        """
+        Encrypt the data. Also, update the cipher iv. This is needed for SSLv3
+        and TLS 1.0. For TLS 1.1/1.2, it is overwritten in TLS.post_build().
+        """
+        if False in self.ready.itervalues():
+            raise CipherError, data
+        encryptor = self._cipher.encryptor()
+        tmp = encryptor.update(data) + encryptor.finalize()
+        self.iv = tmp[-self.block_size:]
+        return tmp
+
+    def decrypt(self, data):
+        """
+        Decrypt the data. Also, update the cipher iv. This is needed for SSLv3
+        and TLS 1.0. For TLS 1.1/1.2, it is overwritten in TLS.pre_dissect().
+        If we lack the key, we raise a CipherError which contains the input.
+        """
+        if False in self.ready.itervalues():
+            raise CipherError, data
+        decryptor = self._cipher.decryptor()
+        tmp = decryptor.update(data) + decryptor.finalize()
+        self.iv = data[-self.block_size:]
+        return tmp
+
+
+class Cipher_AES_128_CBC(_BlockCipher):
+    pc_cls = algorithms.AES
+    pc_cls_mode = modes.CBC
+    block_size = 16
+    key_len = 16
+
+class Cipher_AES_256_CBC(Cipher_AES_128_CBC):
+    key_len = 32
+
+
+class Cipher_CAMELLIA_128_CBC(_BlockCipher):
+    pc_cls = algorithms.Camellia
+    pc_cls_mode = modes.CBC
+    block_size = 16
+    key_len = 16
+
+class Cipher_CAMELLIA_256_CBC(Cipher_CAMELLIA_128_CBC):
+    key_len = 32
+
+
+### Mostly deprecated ciphers
+
+class Cipher_3DES_EDE_CBC(_BlockCipher):
+    pc_cls = algorithms.TripleDES
+    pc_cls_mode = modes.CBC
+    block_size = 8
+    key_len = 24
+
+class Cipher_IDEA_CBC(_BlockCipher):
+    pc_cls = algorithms.IDEA
+    pc_cls_mode = modes.CBC
+    block_size = 8
+    key_len = 16
+
+class Cipher_SEED_CBC(_BlockCipher):
+    pc_cls = algorithms.SEED
+    pc_cls_mode = modes.CBC
+    block_size = 16
+    key_len = 16
+
+#class Cipher_DES_CBC(_BlockCipher):
+#    pc_cls = algorithms.DES    # no support in the cryptography library
+#    pc_cls_mode = modes.CBC
+#    block_size = 8
+#    key_len = 8
+
+#class Cipher_DES40_CBC(Cipher_DES_CBC):
+#    """
+#    This is an export cipher example. The key length has been weakened to 5
+#    random bytes (i.e. 5 bytes will be extracted from the master_secret).
+#    Yet, we still need to know the original length which will actually be
+#    fed into the encryption algorithm. This is what expanded_key_len
+#    is for, and it gets used in PRF.postprocess_key_for_export().
+#    We never define this attribute with non-export ciphers.
+#    """
+#    key_len = 5
+#    expanded_key_len = 8
+
+#class Cipher_RC2_CBC_40(_BlockCipher): # RFC 2268
+#    pc_cls = ARC2              # no support in the cryptography library
+#    pc_cls_mode = modes.CBC
+#    block_size = 8
+#    key_len = 5
+#    expanded_key_len = 16
+
diff --git a/scapy/layers/tls/crypto/cipher_stream.py b/scapy/layers/tls/crypto/cipher_stream.py
new file mode 100644
index 0000000000000000000000000000000000000000..7a403f3cad91da287bf25d508c16249533e125cc
--- /dev/null
+++ b/scapy/layers/tls/crypto/cipher_stream.py
@@ -0,0 +1,98 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+Stream ciphers.
+"""
+
+from cryptography.hazmat.primitives.ciphers import Cipher, algorithms
+from cryptography.hazmat.backends import default_backend
+
+from scapy.layers.tls.crypto.ciphers import CipherError
+
+
+tls_stream_cipher_algs = {}
+
+class _StreamCipherMetaclass(type):
+    """
+    Cipher classes are automatically registered through this metaclass.
+    Furthermore, their name attribute is extracted from their class name.
+    """
+    def __new__(cls, ciph_name, bases, dct):
+        if ciph_name != "_StreamCipher":
+            dct["name"] = ciph_name[7:]     # remove leading "Cipher_"
+        the_class = super(_StreamCipherMetaclass, cls).__new__(cls, ciph_name,
+                                                               bases, dct)
+        if ciph_name != "_StreamCipher":
+            tls_stream_cipher_algs[ciph_name[7:]] = the_class
+        return the_class
+
+
+class _StreamCipher(object):
+    __metaclass__ = _StreamCipherMetaclass
+    type = "stream"
+
+    def __init__(self, key=None):
+        """
+        Note that we have to keep the encryption/decryption state in unique
+        encryptor and decryptor objects. This differs from _BlockCipher.
+        """
+        self.ready = {"key":True}
+        if key is None:
+            self.ready["key"] = False
+            key = "\0" * self.key_len
+
+        # we use super() in order to avoid any deadlock with __setattr__
+        super(_StreamCipher, self).__setattr__("key", key)
+
+        self._cipher = Cipher(self.pc_cls(key),
+                              mode=None,
+                              backend=default_backend())
+        self.encryptor = self._cipher.encryptor()
+        self.decryptor = self._cipher.decryptor()
+
+    def __setattr__(self, name, val):
+        if name == "key":
+            if self._cipher is not None:
+                self._cipher.algorithm.key = val
+            self.ready["key"] = True
+        super(_StreamCipher, self).__setattr__(name, val)
+
+    def encrypt(self, data):
+        if False in self.ready.itervalues():
+            raise CipherError, data
+        return self.encryptor.update(data)
+
+    def decrypt(self, data):
+        if False in self.ready.itervalues():
+            raise CipherError, data
+        return self.decryptor.update(data)
+
+
+class Cipher_RC4_40(_StreamCipher):
+    pc_cls = algorithms.ARC4
+    key_len = 5
+    expanded_key_len = 16
+
+class Cipher_RC4_128(Cipher_RC4_40):
+    key_len = 16
+
+
+class Cipher_NULL(_StreamCipher):
+    key_len = 0
+    expanded_key_len = 0
+
+    def __init__(self, key=None):
+        self.ready = {"key":True}
+        # we use super() in order to avoid any deadlock with __setattr__
+        super(_StreamCipher, self).__setattr__("key", key)
+        self._cipher = None
+
+    def encrypt(self, data):
+        return data
+
+    def decrypt(self, data):
+        return data
+
diff --git a/scapy/layers/tls/crypto/ciphers.py b/scapy/layers/tls/crypto/ciphers.py
new file mode 100644
index 0000000000000000000000000000000000000000..331546e2885fe28204cef693a747596fd4aef1b2
--- /dev/null
+++ b/scapy/layers/tls/crypto/ciphers.py
@@ -0,0 +1,28 @@
+
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+TLS ciphers.
+"""
+
+class CipherError(Exception):
+    """
+    Raised when .decrypt() or .auth_decrypt() fails.
+    """
+    pass
+
+
+# We have to keep these imports below CipherError definition
+# in order to avoid circular dependencies.
+from scapy.layers.tls.crypto.cipher_aead import tls_aead_cipher_algs
+from scapy.layers.tls.crypto.cipher_block import tls_block_cipher_algs
+from scapy.layers.tls.crypto.cipher_stream import tls_stream_cipher_algs
+
+tls_cipher_algs = {}
+tls_cipher_algs.update(tls_block_cipher_algs)
+tls_cipher_algs.update(tls_stream_cipher_algs)
+tls_cipher_algs.update(tls_aead_cipher_algs)
+
diff --git a/scapy/layers/tls/crypto/compression.py b/scapy/layers/tls/crypto/compression.py
new file mode 100644
index 0000000000000000000000000000000000000000..52d60e73a199122f6a272c768135100c3a54420e
--- /dev/null
+++ b/scapy/layers/tls/crypto/compression.py
@@ -0,0 +1,84 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+TLS compression.
+"""
+
+import zlib
+
+from scapy.error import warning
+
+
+_tls_compression_algs = {}
+_tls_compression_algs_cls = {}
+
+class _GenericCompMetaclass(type):
+    """
+    Compression classes are automatically registered through this metaclass.
+    """
+    def __new__(cls, name, bases, dct):
+        the_class = super(_GenericCompMetaclass, cls).__new__(cls, name,
+                                                              bases, dct)
+        comp_name = dct.get("name")
+        val = dct.get("val")
+        if comp_name:
+            _tls_compression_algs[val] = comp_name
+            _tls_compression_algs_cls[val] = the_class
+        return the_class
+
+
+class _GenericComp(object):
+    __metaclass__ = _GenericCompMetaclass
+
+
+class Comp_NULL(_GenericComp):
+    """
+    The default and advised compression method for TLS: doing nothing.
+    """
+    name = "null"
+    val = 0
+
+    def compress(self, s):
+        return s
+
+    def decompress(self, s):
+        return s
+
+class Comp_Deflate(_GenericComp):
+    """
+    DEFLATE algorithm, specified for TLS by RFC 3749.
+    """
+    name = "deflate"
+    val = 1
+
+    def compress(self, s):
+        tmp = self.compress_state.compress(s)
+        tmp += self.compress_state.flush(zlib.Z_FULL_FLUSH)
+        return tmp
+
+    def decompress(self, s):
+        return self.decompress_state.decompress(s)
+
+    def __init__(self):
+        self.compress_state = zlib.compressobj()
+        self.decompress_state = zlib.decompressobj()
+
+class Comp_LZS(_GenericComp):
+    """
+    Lempel-Zic-Stac (LZS) algorithm, specified for TLS by RFC 3943.
+    XXX No support for now.
+    """
+    name = "LZS"
+    val = 64
+
+    def compress(self, s):
+        warning("LZS Compression algorithm is not implemented yet")
+        return s
+
+    def decompress(self, s):
+        warning("LZS Compression algorithm is not implemented yet")
+        return s
+
diff --git a/scapy/layers/tls/crypto/curves.py b/scapy/layers/tls/crypto/curves.py
index 0512766136a7b547056ed67d231c0d9585529501..9a1d875e6930631e36693050da797891d431424b 100644
--- a/scapy/layers/tls/crypto/curves.py
+++ b/scapy/layers/tls/crypto/curves.py
@@ -5,402 +5,265 @@
 
 """
 Implicit elliptic curves.
-"""
-
-# Recommended curve parameters from www.secg.org/SEC2-Ver-1.0.pdf
-# and www.ecc-brainpool.org/download/Domain-parameters.pdf
-# Note that this module will overwrite curves from python-ecdsa.
-
-import math
-from ecdsa.ellipticcurve import CurveFp, Point
-from ecdsa.curves import Curve
-from ecdsa.numbertheory import square_root_mod_prime
-
-from scapy.utils import long_converter, binrepr
-from scapy.layers.tls.crypto.pkcs1 import pkcs_i2osp, pkcs_os2ip
-
-
-##############################################################
-# Some helpers
-##############################################################
-
-def encode_point(point, point_format=0):
-    """
-    Return a string representation of the Point p, according to point_format.
-    """
-    pLen = len(binrepr(point.curve().p()))
-    x = pkcs_i2osp(point.x(), math.ceil(pLen/8))
-    y = pkcs_i2osp(point.y(), math.ceil(pLen/8))
-    if point_format == 0:
-        frmt = '\x04'
-    elif point_format == 1:
-        frmt = chr(2 + y%2)
-        y = ''
-    else:
-        raise Exception("No support for point_format %d" % point_format)
-    return frmt + x + y
-
-def extract_coordinates(g, curve):
-    """
-    Return the coordinates x and y as integers,
-    regardless of the point format of string g.
-    Second expected parameter is a CurveFp.
-    """
-    p = curve.p()
-    point_format = g[0]
-    point = g[1:]
-    if point_format == '\x04':
-        point_len = len(point)
-        if point_len % 2 != 0:
-            raise Exception("Point length is not even.")
-        x_bytes = point[:point_len>>1]
-        x = pkcs_os2ip(x_bytes) % p
-        y_bytes = point[point_len>>1:]
-        y = pkcs_os2ip(y_bytes) % p
-    elif point_format in ['\x02', '\x03']:
-        x_bytes = point
-        x = pkcs_os2ip(x_bytes) % p
-        # perform the y coordinate computation with self.tls_ec
-        y_square = (x*x*x + curve.a()*x + curve.b()) % p
-        y = square_root_mod_prime(y_square, p)
-        y_parity = ord(point_format) % 2    # \x02 means even, \x03 means odd
-        if y % 2 != y_parity:
-            y = -y % p
-    else:
-        raise Exception("Point starts with %s. This encoding "
-                        "is not recognized." % repr(point_format))
-    if not curve.contains_point(x, y):
-        raise Exception("The point we extracted does not belong on the curve!")
-    return x, y
 
-def import_curve(p, a, b, g, r, name="dummyName", oid=(1, 3, 132, 0, 0xff)):
-    """
-    Create an ecdsa.curves.Curve from the usual parameters.
-    Arguments may be either octet strings or integers,
-    except g which we expect to be an octet string.
-    """
-    if isinstance(p, str):
-        p = pkcs_os2ip(p)
-    if isinstance(a, str):
-        a = pkcs_os2ip(a)
-    if isinstance(b, str):
-        b = pkcs_os2ip(b)
-    if isinstance(r, str):
-        r = pkcs_os2ip(r)
-    curve = CurveFp(p, a, b)
-    x, y = extract_coordinates(g, curve)
-    generator = Point(curve, x, y, r)
-    return Curve(name, curve, generator, oid)
+Recommended curve parameters from www.secg.org/SEC2-Ver-1.0.pdf
+and www.ecc-brainpool.org/download/Domain-parameters.pdf
 
+This is a ghost file since the shift from 'ecdsa' to 'cryptography' lib.
+Part of the code has been kept, but commented out, in case anyone would like
+to improve ECC support in 'cryptography' (namely for the compressed point
+format and additional curves).
+"""
 
-##############################################################
-# Named curves
-##############################################################
-
-# We always provide _a as a positive integer.
-
-_p          = long_converter("""
-              ffffffff ffffffff ffffffff fffffffe ffffac73""")
-_a          = 0
-_b          = 7
-_Gx         = long_converter("""
-              3b4c382c e37aa192 a4019e76 3036f4f5 dd4d7ebb""")
-_Gy         = long_converter("""
-              938cf935 318fdced 6bc28286 531733c3 f03c4fee""")
-_r          = long_converter("""01
-              00000000 00000000 0001b8fa 16dfab9a ca16b6b3""")
-curve       = CurveFp(_p, _a, _b)
-generator   = Point(curve, _Gx, _Gy, _r)
-SECP160k1   = Curve("SECP160k1", curve, generator,
-                    (1, 3, 132, 0, 9), "secp160k1")
-
-_p          = long_converter("""
-              ffffffff ffffffff ffffffff ffffffff 7fffffff""")
-_a          = -3 % _p
-_b          = long_converter("""
-              1c97befc 54bd7a8b 65acf89f 81d4d4ad c565fa45""")
-_Gx         = long_converter("""
-              4a96b568 8ef57328 46646989 68c38bb9 13cbfc82""")
-_Gy         = long_converter("""
-              23a62855 3168947d 59dcc912 04235137 7ac5fb32""")
-_r          = long_converter("""01
-              00000000 00000000 0001f4c8 f927aed3 ca752257""")
-curve       = CurveFp(_p, _a, _b)
-generator   = Point(curve, _Gx, _Gy, _r)
-SECP160r1   = Curve("SECP160r1", curve, generator,
-                    (1, 3, 132, 0, 8), "secp160r1")
-
-_p          = long_converter("""
-              ffffffff ffffffff ffffffff fffffffe ffffac73""")
-_a          = -3 % _p
-_b          = long_converter("""
-              b4e134d3 fb59eb8b ab572749 04664d5a f50388ba""")
-_Gx         = long_converter("""
-              52dcb034 293a117e 1f4ff11b 30f7199d 3144ce6d""")
-_Gy         = long_converter("""
-              feaffef2 e331f296 e071fa0d f9982cfe a7d43f2e""")
-_r          = long_converter("""01
-              00000000 00000000 0000351e e786a818 f3a1a16b""")
-curve       = CurveFp(_p, _a, _b)
-generator   = Point(curve, _Gx, _Gy, _r)
-SECP160r2   = Curve("SECP160r2", curve, generator,
-                    (1, 3, 132, 0, 30), "secp160r2")
-
-_p          = long_converter("""
-              ffffffff ffffffff ffffffff ffffffff fffffffe ffffee37""")
-_a          = 0
-_b          = 3
-_Gx         = long_converter("""
-              db4ff10e c057e9ae 26b07d02 80b7f434 1da5d1b1 eae06c7d""")
-_Gy         = long_converter("""
-              9b2f2f6d 9c5628a7 844163d0 15be8634 4082aa88 d95e2f9d""")
-_r          = long_converter("""
-              ffffffff ffffffff fffffffe 26f2fc17 0f69466a 74defd8d""")
-curve       = CurveFp(_p, _a, _b)
-generator   = Point(curve, _Gx, _Gy, _r)
-SECP192k1   = Curve("SECP192k1", curve, generator,
-                    (1, 3, 132, 0, 31), "secp192k1")
-
-_p          = long_converter("""
-              ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff""")
-_a          = -3 % _p
-_b          = long_converter("""
-              64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1""")
-_Gx         = long_converter("""
-              188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012""")
-_Gy         = long_converter("""
-              07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811""")
-_r          = long_converter("""
-              ffffffff ffffffff ffffffff 99def836 146bc9b1 b4d22831""")
-curve       = CurveFp(_p, _a, _b)
-generator   = Point(curve, _Gx, _Gy, _r)
-SECP192r1   = Curve("SECP192r1", curve, generator,
-                    (1, 2, 840, 10045, 3, 1, 1), "prime192v1")
-
-_p          = long_converter("""
-              ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe
-              ffffe56d""")
-_a          = 0
-_b          = 5
-_Gx         = long_converter("""
-              a1455b33 4df099df 30fc28a1 69a467e9 e47075a9 0f7e650e
-              b6b7a45c""")
-_Gy         = long_converter("""
-              7e089fed 7fba3442 82cafbd6 f7e319f7 c0b0bd59 e2ca4bdb
-              556d61a5""")
-_r          = long_converter("""01
-              00000000 00000000 00000000 0001dce8 d2ec6184 caf0a971
-              769fb1f7""")
-curve       = CurveFp(_p, _a, _b)
-generator   = Point(curve, _Gx, _Gy, _r)
-SECP224k1   = Curve("SECP224k1", curve, generator,
-                    (1, 3, 132, 0, 32), "secp224k1")
+#import math
+#
+#from scapy.utils import long_converter, binrepr
+#from scapy.layers.tls.crypto.pkcs1 import pkcs_i2osp, pkcs_os2ip
+#
+#
+#def encode_point(point, point_format=0):
+#    """
+#    Return a string representation of the Point p, according to point_format.
+#    """
+#    pLen = len(binrepr(point.curve().p()))
+#    x = pkcs_i2osp(point.x(), math.ceil(pLen/8))
+#    y = pkcs_i2osp(point.y(), math.ceil(pLen/8))
+#    if point_format == 0:
+#        frmt = '\x04'
+#    elif point_format == 1:
+#        frmt = chr(2 + y%2)
+#        y = ''
+#    else:
+#        raise Exception("No support for point_format %d" % point_format)
+#    return frmt + x + y
+#
+#
+#try:
+#    import ecdsa
+#    ecdsa_support = True
+#except ImportError:
+#    import logging
+#    log_loading = logging.getLogger("scapy.loading")
+#    log_loading.info("Can't import python ecdsa lib. No curves.")
+#
+#
+#if ecdsa_support:
+#
+#    from ecdsa.ellipticcurve import CurveFp, Point
+#    from ecdsa.curves import Curve
+#    from ecdsa.numbertheory import square_root_mod_prime
+#
+#
+#    def extract_coordinates(g, curve):
+#        """
+#        Return the coordinates x and y as integers,
+#        regardless of the point format of string g.
+#        Second expected parameter is a CurveFp.
+#        """
+#        p = curve.p()
+#        point_format = g[0]
+#        point = g[1:]
+#        if point_format == '\x04':
+#            point_len = len(point)
+#            if point_len % 2 != 0:
+#                raise Exception("Point length is not even.")
+#            x_bytes = point[:point_len>>1]
+#            x = pkcs_os2ip(x_bytes) % p
+#            y_bytes = point[point_len>>1:]
+#            y = pkcs_os2ip(y_bytes) % p
+#        elif point_format in ['\x02', '\x03']:
+#            x_bytes = point
+#            x = pkcs_os2ip(x_bytes) % p
+#            # perform the y coordinate computation with self.tls_ec
+#            y_square = (x*x*x + curve.a()*x + curve.b()) % p
+#            y = square_root_mod_prime(y_square, p)
+#            y_parity = ord(point_format) % 2    # \x02 means even, \x03 means odd
+#            if y % 2 != y_parity:
+#                y = -y % p
+#        else:
+#            raise Exception("Point starts with %s. This encoding "
+#                            "is not recognized." % repr(point_format))
+#        if not curve.contains_point(x, y):
+#            raise Exception("The point we extracted does not belong on the curve!")
+#        return x, y
+#
+#    def import_curve(p, a, b, g, r, name="dummyName", oid=(1, 3, 132, 0, 0xff)):
+#        """
+#        Create an ecdsa.curves.Curve from the usual parameters.
+#        Arguments may be either octet strings or integers,
+#        except g which we expect to be an octet string.
+#        """
+#        if isinstance(p, str):
+#            p = pkcs_os2ip(p)
+#        if isinstance(a, str):
+#            a = pkcs_os2ip(a)
+#        if isinstance(b, str):
+#            b = pkcs_os2ip(b)
+#        if isinstance(r, str):
+#            r = pkcs_os2ip(r)
+#        curve = CurveFp(p, a, b)
+#        x, y = extract_coordinates(g, curve)
+#        generator = Point(curve, x, y, r)
+#        return Curve(name, curve, generator, oid)
 
-_p          = long_converter("""
-              ffffffff ffffffff ffffffff ffffffff 00000000 00000000
-              00000001""")
-_a          = -3 % _p
-_b          = long_converter("""
-              b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943
-              2355ffb4""")
-_Gx         = long_converter("""
-              b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6
-              115c1d21""")
-_Gy         = long_converter("""
-              bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199
-              85007e34""")
-_r          = long_converter("""
-              ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945
-              5c5c2a3d""")
-curve       = CurveFp(_p, _a, _b)
-generator   = Point(curve, _Gx, _Gy, _r)
-SECP224r1   = Curve("SECP224r1", curve, generator,
-                    (1, 3, 132, 0, 33), "secp224r1")
 
-# (already defined as SECP256k1 by python-ecdsa)
-_p          = long_converter("""
-              ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
-              fffffffe fffffc2f""")
-_a          = 0
-_b          = 7
-_Gx         = long_converter("""
-              79be667e f9dcbbac 55a06295 ce870b07 029bfcdb 2dce28d9
-              59f2815b 16f81798""")
-_Gy         = long_converter("""
-              483ada77 26a3c465 5da4fbfc 0e1108a8 fd17b448 a6855419
-              9c47d08f fb10d4b8""")
-_r          = long_converter("""
-              ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b
-              bfd25e8c d0364141""")
-curve       = CurveFp(_p, _a, _b)
-generator   = Point(curve, _Gx, _Gy, _r)
-SECP256k1   = Curve("SECP256k1", curve, generator,
-                    (1, 3, 132, 0, 10), "secp256k1")
+    ### Named curves
 
-_p          = long_converter("""
-              ffffffff 00000001 00000000 00000000 00000000 ffffffff
-              ffffffff ffffffff""")
-_a          = -3 % _p
-_b          = long_converter("""
-              5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6
-              3bce3c3e 27d2604b""")
-_Gx         = long_converter("""
-              6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0
-              f4a13945 d898c296""")
-_Gy         = long_converter("""
-              4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece
-              cbb64068 37bf51f5""")
-_r          = long_converter("""
-              ffffffff 00000000 ffffffff ffffffff bce6faad a7179e84
-              f3b9cac2 fc632551""")
-curve       = CurveFp(_p, _a, _b)
-generator   = Point(curve, _Gx, _Gy, _r)
-SECP256r1   = Curve("SECP256r1", curve, generator,
-                    (1, 2, 840, 10045, 3, 1, 7), "prime256v1")
+    # We always provide _a as a positive integer.
 
-_p          = long_converter("""
-              ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
-              ffffffff fffffffe ffffffff 00000000 00000000 ffffffff""")
-_a          = -3 % _p
-_b          = long_converter("""
-              b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112
-              0314088f 5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef""")
-_Gx         = long_converter("""
-              aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98
-              59f741e0 82542a38 5502f25d bf55296c 3a545e38 72760ab7""")
-_Gy         = long_converter("""
-              3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c
-              e9da3113 b5f0b8c0 0a60b1ce 1d7e819d 7a431d7c 90ea0e5f""")
-_r          = long_converter("""
-              ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
-              c7634d81 f4372ddf 581a0db2 48b0a77a ecec196a ccc52973""")
-curve       = CurveFp(_p, _a, _b)
-generator   = Point(curve, _Gx, _Gy, _r)
-SECP384r1   = Curve("SECP384r1", curve, generator,
-                    (1, 3, 132, 0, 34), "secp384r1")
+#    _p          = long_converter("""
+#                  ffffffff ffffffff ffffffff fffffffe ffffac73""")
+#    _a          = 0
+#    _b          = 7
+#    _Gx         = long_converter("""
+#                  3b4c382c e37aa192 a4019e76 3036f4f5 dd4d7ebb""")
+#    _Gy         = long_converter("""
+#                  938cf935 318fdced 6bc28286 531733c3 f03c4fee""")
+#    _r          = long_converter("""01
+#                  00000000 00000000 0001b8fa 16dfab9a ca16b6b3""")
+#    curve       = CurveFp(_p, _a, _b)
+#    generator   = Point(curve, _Gx, _Gy, _r)
+#    SECP160k1   = Curve("SECP160k1", curve, generator,
+#                        (1, 3, 132, 0, 9), "secp160k1")
 
-_p          = long_converter("""
-                  01ff ffffffff ffffffff ffffffff ffffffff ffffffff
-              ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
-              ffffffff ffffffff ffffffff ffffffff ffffffff""")
-_a          = -3 % _p
-_b          = long_converter("""
-                  0051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b
-              99b315f3 b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd
-              3bb1bf07 3573df88 3d2c34f1 ef451fd4 6b503f00""")
-_Gx         = long_converter("""
-                  00c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139
-              053fb521 f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127
-              a2ffa8de 3348b3c1 856a429b f97e7e31 c2e5bd66""")
-_Gy         = long_converter("""
-                  0118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449
-              579b4468 17afbd17 273e662c 97ee7299 5ef42640 c550b901
-              3fad0761 353c7086 a272c240 88be9476 9fd16650""")
-_r          = long_converter("""
-                  01ff ffffffff ffffffff ffffffff ffffffff ffffffff
-              ffffffff ffffffff fffffffa 51868783 bf2f966b 7fcc0148
-              f709a5d0 3bb5c9b8 899c47ae bb6fb71e 91386409""")
-curve       = CurveFp(_p, _a, _b)
-generator   = Point(curve, _Gx, _Gy, _r)
-SECP521r1   = Curve("SECP521r1", curve, generator,
-                    (1, 3, 132, 0, 35), "secp521r1")
+#    _p          = long_converter("""
+#                  ffffffff ffffffff ffffffff ffffffff 7fffffff""")
+#    _a          = -3 % _p
+#    _b          = long_converter("""
+#                  1c97befc 54bd7a8b 65acf89f 81d4d4ad c565fa45""")
+#    _Gx         = long_converter("""
+#                  4a96b568 8ef57328 46646989 68c38bb9 13cbfc82""")
+#    _Gy         = long_converter("""
+#                  23a62855 3168947d 59dcc912 04235137 7ac5fb32""")
+#    _r          = long_converter("""01
+#                  00000000 00000000 0001f4c8 f927aed3 ca752257""")
+#    curve       = CurveFp(_p, _a, _b)
+#    generator   = Point(curve, _Gx, _Gy, _r)
+#    SECP160r1   = Curve("SECP160r1", curve, generator,
+#                        (1, 3, 132, 0, 8), "secp160r1")
 
-_p          = long_converter("""
-              A9FB57DB A1EEA9BC 3E660A90 9D838D72 6E3BF623 D5262028
-              2013481D 1F6E5377""")
-_a          = long_converter("""
-              7D5A0975 FC2C3057 EEF67530 417AFFE7 FB8055C1 26DC5C6C
-              E94A4B44 F330B5D9""")
-_b          = long_converter("""
-              26DC5C6C E94A4B44 F330B5D9 BBD77CBF 95841629 5CF7E1CE
-              6BCCDC18 FF8C07B6""")
-_Gx         = long_converter("""
-              8BD2AEB9 CB7E57CB 2C4B482F FC81B7AF B9DE27E1 E3BD23C2
-              3A4453BD 9ACE3262""")
-_Gy         = long_converter("""
-              547EF835 C3DAC4FD 97F8461A 14611DC9 C2774513 2DED8E54
-              5C1D54C7 2F046997""")
-_r          = long_converter("""
-              A9FB57DB A1EEA9BC 3E660A90 9D838D71 8C397AA3 B561A6F7
-              901E0E82 974856A7""")
-curve       = CurveFp(_p, _a, _b)
-generator   = Point(curve, _Gx, _Gy, _r)
-BRNP256r1   = Curve("BRNP256r1", curve, generator,
-                    (1, 3, 36, 3, 3, 2, 8, 1, 1, 7), "brainpoolP256r1")
+#    _p          = long_converter("""
+#                  ffffffff ffffffff ffffffff fffffffe ffffac73""")
+#    _a          = -3 % _p
+#    _b          = long_converter("""
+#                  b4e134d3 fb59eb8b ab572749 04664d5a f50388ba""")
+#    _Gx         = long_converter("""
+#                  52dcb034 293a117e 1f4ff11b 30f7199d 3144ce6d""")
+#    _Gy         = long_converter("""
+#                  feaffef2 e331f296 e071fa0d f9982cfe a7d43f2e""")
+#    _r          = long_converter("""01
+#                  00000000 00000000 0000351e e786a818 f3a1a16b""")
+#    curve       = CurveFp(_p, _a, _b)
+#    generator   = Point(curve, _Gx, _Gy, _r)
+#    SECP160r2   = Curve("SECP160r2", curve, generator,
+#                        (1, 3, 132, 0, 30), "secp160r2")
 
-_p          = long_converter("""
-              8CB91E82 A3386D28 0F5D6F7E 50E641DF 152F7109 ED5456B4
-              12B1DA19 7FB71123 ACD3A729 901D1A71 87470013 3107EC53""")
-_a          = long_converter("""
-              7BC382C6 3D8C150C 3C72080A CE05AFA0 C2BEA28E 4FB22787
-              139165EF BA91F90F 8AA5814A 503AD4EB 04A8C7DD 22CE2826""")
-_b          = long_converter("""
-              04A8C7DD 22CE2826 8B39B554 16F0447C 2FB77DE1 07DCD2A6
-              2E880EA5 3EEB62D5 7CB43902 95DBC994 3AB78696 FA504C11""")
-_Gx         = long_converter("""
-              1D1C64F0 68CF45FF A2A63A81 B7C13F6B 8847A3E7 7EF14FE3
-              DB7FCAFE 0CBD10E8 E826E034 36D646AA EF87B2E2 47D4AF1E""")
-_Gy         = long_converter("""
-              8ABE1D75 20F9C2A4 5CB1EB8E 95CFD552 62B70B29 FEEC5864
-              E19C054F F9912928 0E464621 77918111 42820341 263C5315""")
-_r          = long_converter("""
-              8CB91E82 A3386D28 0F5D6F7E 50E641DF 152F7109 ED5456B3
-              1F166E6C AC0425A7 CF3AB6AF 6B7FC310 3B883202 E9046565""")
-curve       = CurveFp(_p, _a, _b)
-generator   = Point(curve, _Gx, _Gy, _r)
-BRNP384r1   = Curve("BRNP384r1", curve, generator,
-                    (1, 3, 36, 3, 3, 2, 8, 1, 1, 11), "brainpoolP384r1")
+#    _p          = long_converter("""
+#                  ffffffff ffffffff ffffffff ffffffff fffffffe ffffee37""")
+#    _a          = 0
+#    _b          = 3
+#    _Gx         = long_converter("""
+#                  db4ff10e c057e9ae 26b07d02 80b7f434 1da5d1b1 eae06c7d""")
+#    _Gy         = long_converter("""
+#                  9b2f2f6d 9c5628a7 844163d0 15be8634 4082aa88 d95e2f9d""")
+#    _r          = long_converter("""
+#                  ffffffff ffffffff fffffffe 26f2fc17 0f69466a 74defd8d""")
+#    curve       = CurveFp(_p, _a, _b)
+#    generator   = Point(curve, _Gx, _Gy, _r)
+#    SECP192k1   = Curve("SECP192k1", curve, generator,
+#                        (1, 3, 132, 0, 31), "secp192k1")
 
-_p          = long_converter("""
-              AADD9DB8 DBE9C48B 3FD4E6AE 33C9FC07 CB308DB3 B3C9D20E
-              D6639CCA 70330871 7D4D9B00 9BC66842 AECDA12A E6A380E6
-              2881FF2F 2D82C685 28AA6056 583A48F3""")
-_a          = long_converter("""
-              7830A331 8B603B89 E2327145 AC234CC5 94CBDD8D 3DF91610
-              A83441CA EA9863BC 2DED5D5A A8253AA1 0A2EF1C9 8B9AC8B5
-              7F1117A7 2BF2C7B9 E7C1AC4D 77FC94CA""")
-_b          = long_converter("""
-              3DF91610 A83441CA EA9863BC 2DED5D5A A8253AA1 0A2EF1C9
-              8B9AC8B5 7F1117A7 2BF2C7B9 E7C1AC4D 77FC94CA DC083E67
-              984050B7 5EBAE5DD 2809BD63 8016F723""")
-_Gx         = long_converter("""
-              81AEE4BD D82ED964 5A21322E 9C4C6A93 85ED9F70 B5D916C1
-              B43B62EE F4D0098E FF3B1F78 E2D0D48D 50D1687B 93B97D5F
-              7C6D5047 406A5E68 8B352209 BCB9F822""")
-_Gy         = long_converter("""
-              7DDE385D 566332EC C0EABFA9 CF7822FD F209F700 24A57B1A
-              A000C55B 881F8111 B2DCDE49 4A5F485E 5BCA4BD8 8A2763AE
-              D1CA2B2F A8F05406 78CD1E0F 3AD80892""")
-_r          = long_converter("""
-              AADD9DB8 DBE9C48B 3FD4E6AE 33C9FC07 CB308DB3 B3C9D20E
-              D6639CCA 70330870 553E5C41 4CA92619 41866119 7FAC1047
-              1DB1D381 085DDADD B5879682 9CA90069""")
-curve       = CurveFp(_p, _a, _b)
-generator   = Point(curve, _Gx, _Gy, _r)
-BRNP512r1   = Curve("BRNP512r1", curve, generator,
-                    (1, 3, 36, 3, 3, 2, 8, 1, 1, 13), "brainpoolP512r1")
+#    _p          = long_converter("""
+#                  ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe
+#                  ffffe56d""")
+#    _a          = 0
+#    _b          = 5
+#    _Gx         = long_converter("""
+#                  a1455b33 4df099df 30fc28a1 69a467e9 e47075a9 0f7e650e
+#                  b6b7a45c""")
+#    _Gy         = long_converter("""
+#                  7e089fed 7fba3442 82cafbd6 f7e319f7 c0b0bd59 e2ca4bdb
+#                  556d61a5""")
+#    _r          = long_converter("""01
+#                  00000000 00000000 00000000 0001dce8 d2ec6184 caf0a971
+#                  769fb1f7""")
+#    curve       = CurveFp(_p, _a, _b)
+#    generator   = Point(curve, _Gx, _Gy, _r)
+#    SECP224k1   = Curve("SECP224k1", curve, generator,
+#                        (1, 3, 132, 0, 32), "secp224k1")
 
-# we use IANA identifiers below
-named_curves = { 15: SECP160k1,
-                 16: SECP160r1,
-                 17: SECP160r2,
-                 18: SECP192k1,
-                 19: SECP192r1,
-                 20: SECP224k1,
-                 21: SECP224r1,
-                 22: SECP256k1,
-                 23: SECP256r1,
-                 24: SECP384r1,
-                 25: SECP521r1,
-                 26: BRNP256r1,
-                 27: BRNP384r1,
-                 28: BRNP512r1
-               }
+#    _p          = long_converter("""
+#                  A9FB57DB A1EEA9BC 3E660A90 9D838D72 6E3BF623 D5262028
+#                  2013481D 1F6E5377""")
+#    _a          = long_converter("""
+#                  7D5A0975 FC2C3057 EEF67530 417AFFE7 FB8055C1 26DC5C6C
+#                  E94A4B44 F330B5D9""")
+#    _b          = long_converter("""
+#                  26DC5C6C E94A4B44 F330B5D9 BBD77CBF 95841629 5CF7E1CE
+#                  6BCCDC18 FF8C07B6""")
+#    _Gx         = long_converter("""
+#                  8BD2AEB9 CB7E57CB 2C4B482F FC81B7AF B9DE27E1 E3BD23C2
+#                  3A4453BD 9ACE3262""")
+#    _Gy         = long_converter("""
+#                  547EF835 C3DAC4FD 97F8461A 14611DC9 C2774513 2DED8E54
+#                  5C1D54C7 2F046997""")
+#    _r          = long_converter("""
+#                  A9FB57DB A1EEA9BC 3E660A90 9D838D71 8C397AA3 B561A6F7
+#                  901E0E82 974856A7""")
+#    curve       = CurveFp(_p, _a, _b)
+#    generator   = Point(curve, _Gx, _Gy, _r)
+#    BRNP256r1   = Curve("BRNP256r1", curve, generator,
+#                        (1, 3, 36, 3, 3, 2, 8, 1, 1, 7), "brainpoolP256r1")
 
-for cid, c in named_curves.iteritems():
-    c.curve_id = cid
+#    _p          = long_converter("""
+#                  8CB91E82 A3386D28 0F5D6F7E 50E641DF 152F7109 ED5456B4
+#                  12B1DA19 7FB71123 ACD3A729 901D1A71 87470013 3107EC53""")
+#    _a          = long_converter("""
+#                  7BC382C6 3D8C150C 3C72080A CE05AFA0 C2BEA28E 4FB22787
+#                  139165EF BA91F90F 8AA5814A 503AD4EB 04A8C7DD 22CE2826""")
+#    _b          = long_converter("""
+#                  04A8C7DD 22CE2826 8B39B554 16F0447C 2FB77DE1 07DCD2A6
+#                  2E880EA5 3EEB62D5 7CB43902 95DBC994 3AB78696 FA504C11""")
+#    _Gx         = long_converter("""
+#                  1D1C64F0 68CF45FF A2A63A81 B7C13F6B 8847A3E7 7EF14FE3
+#                  DB7FCAFE 0CBD10E8 E826E034 36D646AA EF87B2E2 47D4AF1E""")
+#    _Gy         = long_converter("""
+#                  8ABE1D75 20F9C2A4 5CB1EB8E 95CFD552 62B70B29 FEEC5864
+#                  E19C054F F9912928 0E464621 77918111 42820341 263C5315""")
+#    _r          = long_converter("""
+#                  8CB91E82 A3386D28 0F5D6F7E 50E641DF 152F7109 ED5456B3
+#                  1F166E6C AC0425A7 CF3AB6AF 6B7FC310 3B883202 E9046565""")
+#    curve       = CurveFp(_p, _a, _b)
+#    generator   = Point(curve, _Gx, _Gy, _r)
+#    BRNP384r1   = Curve("BRNP384r1", curve, generator,
+#                        (1, 3, 36, 3, 3, 2, 8, 1, 1, 11), "brainpoolP384r1")
 
-# replace/fill previous named curves
-import ecdsa.curves
-ecdsa.curves.curves = named_curves.values()
+#    _p          = long_converter("""
+#                  AADD9DB8 DBE9C48B 3FD4E6AE 33C9FC07 CB308DB3 B3C9D20E
+#                  D6639CCA 70330871 7D4D9B00 9BC66842 AECDA12A E6A380E6
+#                  2881FF2F 2D82C685 28AA6056 583A48F3""")
+#    _a          = long_converter("""
+#                  7830A331 8B603B89 E2327145 AC234CC5 94CBDD8D 3DF91610
+#                  A83441CA EA9863BC 2DED5D5A A8253AA1 0A2EF1C9 8B9AC8B5
+#                  7F1117A7 2BF2C7B9 E7C1AC4D 77FC94CA""")
+#    _b          = long_converter("""
+#                  3DF91610 A83441CA EA9863BC 2DED5D5A A8253AA1 0A2EF1C9
+#                  8B9AC8B5 7F1117A7 2BF2C7B9 E7C1AC4D 77FC94CA DC083E67
+#                  984050B7 5EBAE5DD 2809BD63 8016F723""")
+#    _Gx         = long_converter("""
+#                  81AEE4BD D82ED964 5A21322E 9C4C6A93 85ED9F70 B5D916C1
+#                  B43B62EE F4D0098E FF3B1F78 E2D0D48D 50D1687B 93B97D5F
+#                  7C6D5047 406A5E68 8B352209 BCB9F822""")
+#    _Gy         = long_converter("""
+#                  7DDE385D 566332EC C0EABFA9 CF7822FD F209F700 24A57B1A
+#                  A000C55B 881F8111 B2DCDE49 4A5F485E 5BCA4BD8 8A2763AE
+#                  D1CA2B2F A8F05406 78CD1E0F 3AD80892""")
+#    _r          = long_converter("""
+#                  AADD9DB8 DBE9C48B 3FD4E6AE 33C9FC07 CB308DB3 B3C9D20E
+#                  D6639CCA 70330870 553E5C41 4CA92619 41866119 7FAC1047
+#                  1DB1D381 085DDADD B5879682 9CA90069""")
+#    curve       = CurveFp(_p, _a, _b)
+#    generator   = Point(curve, _Gx, _Gy, _r)
+#    BRNP512r1   = Curve("BRNP512r1", curve, generator,
+#                        (1, 3, 36, 3, 3, 2, 8, 1, 1, 13), "brainpoolP512r1")
 
diff --git a/scapy/layers/tls/crypto/ffdh.py b/scapy/layers/tls/crypto/ffdh.py
new file mode 100644
index 0000000000000000000000000000000000000000..7451c96e52788284fc101ecf1b149038a66d9657
--- /dev/null
+++ b/scapy/layers/tls/crypto/ffdh.py
@@ -0,0 +1,299 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+This is a register for DH groups from RFC 3526 and RFC 4306.
+XXX These groups (and the ones from RFC 7919) should be registered to
+the cryptography library. And this file should eventually be removed.
+"""
+
+from cryptography.hazmat.backends import default_backend
+from cryptography.hazmat.primitives.asymmetric import dh
+
+from scapy.utils import long_converter
+
+
+class modp768: # From RFC 4306
+    g = 0x02
+    m = long_converter("""
+    FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08
+    8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B
+    302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9
+    A63A3620 FFFFFFFF FFFFFFFF""")
+    mLen = 768
+
+class modp1024: # From RFC 4306
+    g = 0x02
+    m = long_converter("""
+    FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08
+    8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B
+    302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9
+    A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6
+    49286651 ECE65381 FFFFFFFF FFFFFFFF""")
+    mLen  = 1024
+
+class modp1536: # From RFC 3526
+    g = 0x02
+    m = long_converter("""
+    FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+    29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+    EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+    E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+    EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
+    C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
+    83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+    670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF""")
+    mLen  = 1536
+
+class modp2048: # From RFC 3526
+    g = 0x02
+    m = long_converter("""
+    FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+    29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+    EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+    E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+    EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
+    C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
+    83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+    670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
+    E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
+    DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
+    15728E5A 8AACAA68 FFFFFFFF FFFFFFFF""")
+    mLen  = 2048
+
+class modp3072: # From RFC 3526
+    g = 0x02
+    m = long_converter("""
+    FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+    29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+    EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+    E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+    EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
+    C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
+    83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+    670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
+    E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
+    DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
+    15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64
+    ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7
+    ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B
+    F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C
+    BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31
+    43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF""")
+    mLen  = 3072
+
+class modp4096: # From RFC 3526
+    g = 0x02
+    m = long_converter("""
+    FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+    29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+    EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+    E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+    EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
+    C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
+    83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+    670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
+    E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
+    DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
+    15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64
+    ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7
+    ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B
+    F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C
+    BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31
+    43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7
+    88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA
+    2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6
+    287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED
+    1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9
+    93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199
+    FFFFFFFF FFFFFFFF""")
+    mLen  = 4096
+
+class modp6144: # From RFC 3526
+    g = 0x02
+    m = long_converter("""
+    FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08
+    8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B
+    302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9
+    A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6
+    49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8
+    FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+    670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C
+    180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718
+    3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D
+    04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D
+    B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226
+    1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C
+    BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC
+    E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7 88719A10 BDBA5B26
+    99C32718 6AF4E23C 1A946834 B6150BDA 2583E9CA 2AD44CE8 DBBBC2DB
+    04DE8EF9 2E8EFC14 1FBECAA6 287C5947 4E6BC05D 99B2964F A090C3A2
+    233BA186 515BE7ED 1F612970 CEE2D7AF B81BDD76 2170481C D0069127
+    D5B05AA9 93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492
+    36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD F8FF9406
+    AD9E530E E5DB382F 413001AE B06A53ED 9027D831 179727B0 865A8918
+    DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B DB7F1447 E6CC254B 33205151
+    2BD7AF42 6FB8F401 378CD2BF 5983CA01 C64B92EC F032EA15 D1721D03
+    F482D7CE 6E74FEF6 D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F
+    BEC7E8F3 23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA
+    CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328 06A1D58B
+    B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C DA56C9EC 2EF29632
+    387FE8D7 6E3C0468 043E8F66 3F4860EE 12BF2D5B 0B7474D6 E694F91E
+    6DCC4024 FFFFFFFF FFFFFFFF""")
+    mLen = 6144
+
+class modp8192: # From RFC 3526
+    g = 0x02
+    m = long_converter("""
+    FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+    29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+    EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+    E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+    EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
+    C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
+    83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+    670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
+    E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
+    DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
+    15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64
+    ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7
+    ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B
+    F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C
+    BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31
+    43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7
+    88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA
+    2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6
+    287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED
+    1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9
+    93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492
+    36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD
+    F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831
+    179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B
+    DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF
+    5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6
+    D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3
+    23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA
+    CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328
+    06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C
+    DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE
+    12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4
+    38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300
+    741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568
+    3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9
+    22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B
+    4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A
+    062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36
+    4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1
+    B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92
+    4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47
+    9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71
+    60C980DD 98EDD3DF FFFFFFFF FFFFFFFF""")
+    mLen = 8192
+
+_ffdh_raw_params = { 'modp768' : modp768,
+                     'modp1024': modp1024,
+                     'modp1536': modp1536,
+                     'modp2048': modp2048,
+                     'modp3072': modp3072,
+                     'modp4096': modp4096,
+                     'modp6144': modp6144,
+                     'modp8192': modp8192  }
+
+FFDH_GROUPS = {}
+for name, group in _ffdh_raw_params.iteritems():
+    pn = dh.DHParameterNumbers(group.m, group.g)
+    params = pn.parameters(default_backend())
+    FFDH_GROUPS[name] = [params, group.mLen]
+
+
+#from scapy.layers.tls.crypto.pkcs1 import pkcs_os2ip, pkcs_i2osp
+#
+#
+#class FFDHParams(object):
+#    """
+#    Finite-Field Diffie-Hellman parameters.
+#    self.priv is an integer. Its value may remain unknown.
+#    self.pub, self.other_pub, and finally self.secret, are also integers.
+#    Default group parameters relate to the 2048-bit group from RFC 3526.
+#    """
+#    def __init__(self, g=ffdh_params[2048].g,
+#                       m=ffdh_params[2048].m,
+#                       mLen=ffdh_params[2048].mLen):
+#        """
+#           g: group (2, 5, ...). Can be provided as a string or long.
+#           m: prime modulus. Can be provided as a string or long.
+#        mLen: prime modulus length in bits.
+#        """
+#        if type(g) is str:
+#            g = pkcs_os2ip(g)
+#        if type(m) is str:
+#            m = pkcs_os2ip(m)
+#
+#        self.g = long(g)
+#        self.m = long(m)
+#        self.mLen = mLen
+#
+#        self.priv       = None
+#        self.pub        = None
+#        self.other_pub  = None
+#        self.secret     = None
+#
+#    def gen_public_params(self):
+#        """
+#        Generate FFDH public parameter, by choosing a random private
+#        value in ] 0, p-1 [ and then exponentiating the generator of
+#        the group with the private value. The public parameter is
+#        returned as an octet string. The private parameter is internally
+#        available for further secret generation (using .gen_secret()).
+#
+#        Note that 'secret' and 'other_pub' attribute of the instance
+#        are reset by the call.
+#        """
+#        self.other_pub  = None
+#        self.secret     = None
+#
+#        # Private key generation : 0 < x < p-1
+#        x = random.randint(1, self.m-2)
+#        self.priv = x
+#
+#        # Exponentiation
+#        y = pow(self.g, self.priv, self.m)
+#        self.pub = y
+#
+#        # Integer-to-octet-string conversion
+#        y = pkcs_i2osp(y, self.mLen/8)
+#
+#        return y
+#
+#    def gen_secret(self, other_pub):
+#        """
+#        Given the peer's public value 'other_pub' provided as an octet string,
+#        the shared secret is computed by exponentiating the value using
+#        internally stored private value (self.priv, generated during
+#        public_parameter generation using .gen_public_params()).
+#
+#        Computed secret is returned as a bitstring and stored internally.
+#
+#        No specific check is done on 'other_pub' before exponentiation.
+#        """
+#        if type(other_pub) is str:
+#            other_pub = pkcs_os2ip(other_pub)
+#
+#        # Octet-string-to-integer conversion
+#        self.other_pub = other_pub
+#
+#        # Exponentiation
+#        z = pow(other_pub, self.priv, self.m)
+#
+#        # Integer-to-octet-string conversion
+#        z = pkcs_i2osp(z, self.mLen/8)
+#        self.secret = z
+#
+#        return z
+#
+#    def check_params(self):
+#        #XXX Do me, maybe
+#        pass
+
diff --git a/scapy/layers/tls/crypto/h_mac.py b/scapy/layers/tls/crypto/h_mac.py
new file mode 100644
index 0000000000000000000000000000000000000000..6be3803b9c41b80050d7a2f5561d0415deddf6dd
--- /dev/null
+++ b/scapy/layers/tls/crypto/h_mac.py
@@ -0,0 +1,107 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+HMAC classes.
+"""
+
+import hmac
+
+from scapy.layers.tls.crypto.hash import tls_hash_algs
+
+
+SSLv3_PAD1_MD5  = "\x36"*48
+SSLv3_PAD1_SHA1 = "\x36"*40
+SSLv3_PAD2_MD5  = "\x5c"*48
+SSLv3_PAD2_SHA1 = "\x5c"*40
+
+tls_hmac_algs = {}
+
+class _GenericHMACMetaclass(type):
+    """
+    HMAC classes are automatically registered through this metaclass.
+    Furthermore, their name attribute is extracted from their class name.
+
+    Note that, when used with TLS, the HMAC key length equates the output of
+    the associated hash function (see RFC 5246, appendix C).
+    Also, we do not need to instantiate the associated hash function.
+    """
+    def __new__(cls, hmac_name, bases, dct):
+        hash_name = hmac_name[5:]               # remove leading "Hmac_"
+        if hmac_name != "_GenericHMAC":
+            dct["name"] = "HMAC-%s" % hash_name
+            dct["hash_alg"] = tls_hash_algs[hash_name]
+            dct["hmac_len"] = tls_hash_algs[hash_name].hash_len
+            dct["key_len"] = dct["hmac_len"]
+        the_class = super(_GenericHMACMetaclass, cls).__new__(cls, hmac_name,
+                                                              bases, dct)
+        if hmac_name != "_GenericHMAC":
+            tls_hmac_algs[dct["name"]] = the_class
+        return the_class
+
+
+class HMACError(Exception):
+    """
+    Raised when HMAC verification fails.
+    """
+    pass
+
+class _GenericHMAC(object):
+    __metaclass__ = _GenericHMACMetaclass
+
+    def __init__(self, key=None):
+        self.key = key
+
+    def digest(self, tbd):
+        if self.key is None:
+            raise HMACError
+        return hmac.new(self.key, tbd, self.hash_alg.hash_cls).digest()
+
+    def digest_sslv3(self, tbd):
+        if self.key is None:
+            raise HMACError
+
+        h = self.hash_alg()
+        if h.name == "SHA":
+            pad1 = SSLv3_PAD1_SHA1
+            pad2 = SSLv3_PAD2_SHA1
+        elif h.name == "MD5":
+            pad1 = SSLv3_PAD1_MD5
+            pad2 = SSLv3_PAD2_MD5
+        else:
+            raise HMACError("Provided hash does not work with SSLv3.")
+
+        return h.digest(self.key + pad2 +
+                        h.digest(self.key + pad1 + tbd))
+
+
+class Hmac_NULL(_GenericHMAC):
+    hmac_len = 0
+    key_len = 0
+
+    def digest(self, tbd):
+        return ""
+
+    def digest_sslv3(self, tbd):
+        return ""
+
+class Hmac_MD5(_GenericHMAC):
+    pass
+
+class Hmac_SHA(_GenericHMAC):
+    pass
+
+class Hmac_SHA224(_GenericHMAC):
+    pass
+
+class Hmac_SHA256(_GenericHMAC):
+    pass
+
+class Hmac_SHA384(_GenericHMAC):
+    pass
+
+class Hmac_SHA512(_GenericHMAC):
+    pass
+
diff --git a/scapy/layers/tls/crypto/hash.py b/scapy/layers/tls/crypto/hash.py
new file mode 100644
index 0000000000000000000000000000000000000000..de735788f41f90181679e059d76badcb3c3edb78
--- /dev/null
+++ b/scapy/layers/tls/crypto/hash.py
@@ -0,0 +1,66 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+Hash classes.
+"""
+
+from hashlib import md5, sha1, sha224, sha256, sha384, sha512
+
+
+tls_hash_algs = {}
+
+class _GenericHashMetaclass(type):
+    """
+    Hash classes are automatically registered through this metaclass.
+    Furthermore, their name attribute is extracted from their class name.
+    """
+    def __new__(cls, hash_name, bases, dct):
+        if hash_name != "_GenericHash":
+            dct["name"] = hash_name[5:]     # remove leading "Hash_"
+        the_class = super(_GenericHashMetaclass, cls).__new__(cls, hash_name,
+                                                              bases, dct)
+        if hash_name != "_GenericHash":
+            tls_hash_algs[hash_name[5:]] = the_class
+        return the_class
+
+
+class _GenericHash(object):
+    __metaclass__ = _GenericHashMetaclass
+
+    def digest(self, tbd):
+        return self.hash_cls(tbd).digest()
+
+
+class Hash_NULL(_GenericHash):
+    hash_len = 0
+
+    def digest(self, tbd):
+        return ""
+
+class Hash_MD5(_GenericHash):
+    hash_cls = md5
+    hash_len = 16
+
+class Hash_SHA(_GenericHash):
+    hash_cls = sha1
+    hash_len = 20
+
+class Hash_SHA224(_GenericHash):
+    hash_cls = sha224
+    hash_len = 28
+
+class Hash_SHA256(_GenericHash):
+    hash_cls = sha256
+    hash_len = 32
+
+class Hash_SHA384(_GenericHash):
+    hash_cls = sha384
+    hash_len = 48
+
+class Hash_SHA512(_GenericHash):
+    hash_cls = sha512
+    hash_len = 64
+
diff --git a/scapy/layers/tls/crypto/kx_algs.py b/scapy/layers/tls/crypto/kx_algs.py
new file mode 100644
index 0000000000000000000000000000000000000000..501e22ff1aad865d5a085b1eb8cd8ad507059946
--- /dev/null
+++ b/scapy/layers/tls/crypto/kx_algs.py
@@ -0,0 +1,179 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+Key Exchange algorithms as listed in appendix C of RFC 4346.
+
+XXX Incomplete support for static DH, DSS, PSK, SRP, KRB and anonymous kx.
+"""
+
+from scapy.layers.tls.keyexchange import (ServerDHParams,
+                                          ServerRSAParams,
+                                          ClientDiffieHellmanPublic,
+                                          ClientECDiffieHellmanPublic,
+                                          _tls_server_ecdh_cls_guess,
+                                          EncryptedPreMasterSecret)
+
+
+tls_kx_algs = {}
+
+class _GenericKXMetaclass(type):
+    """
+    We could try to set server_kx_msg and client_kx_msg while parsing
+    the class name... :)
+    """
+    def __new__(cls, kx_name, bases, dct):
+        if kx_name != "_GenericKX":
+            dct["name"] = kx_name[3:]       # remove leading "KX_"
+        the_class = super(_GenericKXMetaclass, cls).__new__(cls, kx_name,
+                                                            bases, dct)
+        if kx_name:
+            the_class.export = kx_name.endswith("_EXPORT")
+            the_class.anonymous = "_anon_" in kx_name
+            the_class.no_ske = not ("DHE" in kx_name or "_anon_" in kx_name)
+            the_class.no_ske &= not the_class.export
+            tls_kx_algs[kx_name[3:]] = the_class
+        return the_class
+
+
+class _GenericKX:
+    __metaclass__ = _GenericKXMetaclass
+
+
+class KX_NULL(_GenericKX):
+    descr = "No key exchange"
+    server_kx_msg_cls = lambda _,m: None
+    client_kx_msg_cls = None
+
+
+### Standard RSA-authenticated key exchange
+
+class KX_RSA(_GenericKX):
+    descr = "RSA encryption"
+    server_kx_msg_cls = lambda _,m: None
+    client_kx_msg_cls = EncryptedPreMasterSecret
+
+#class KX_DH_RSA(_GenericKX):
+#    descr = "DH with RSA-based certificates"
+#    server_kx_msg_cls = lambda _,m: None
+#    client_kx_msg_cls = None
+
+class KX_DHE_RSA(_GenericKX):
+    descr = "Ephemeral DH with RSA signature"
+    server_kx_msg_cls = lambda _,m: ServerDHParams
+    client_kx_msg_cls = ClientDiffieHellmanPublic
+
+# class KX_ECDH_RSA(_GenericKX):
+#     descr = "ECDH RSA key exchange"
+#     server_kx_msg_cls = lambda _,m: None
+#     client_kx_msg_cls = None
+
+class KX_ECDHE_RSA(_GenericKX):
+    descr = "Ephemeral ECDH with RSA signature"
+    server_kx_msg_cls = lambda _,m: _tls_server_ecdh_cls_guess(m)
+    client_kx_msg_cls = ClientECDiffieHellmanPublic
+
+class KX_RSA_EXPORT(KX_RSA):
+    descr = "RSA encryption, export version"
+    server_kx_msg_cls = lambda _,m: ServerRSAParams
+
+#class KX_DH_RSA_EXPORT(KX_DH_RSA):
+#    descr = "DH with RSA-based certificates - Export version"
+
+class KX_DHE_RSA_EXPORT(KX_DHE_RSA):
+    descr = "Ephemeral DH with RSA signature, export version"
+
+
+### Standard ECDSA-authenticated key exchange
+
+# class KX_ECDH_ECDSA(_GenericKX):
+#     descr = "ECDH ECDSA key exchange"
+#     server_kx_msg_cls = lambda _,m: None
+#     client_kx_msg_cls = None
+
+class KX_ECDHE_ECDSA(_GenericKX):
+   descr = "Ephemeral ECDH with ECDSA signature"
+   server_kx_msg_cls = lambda _,m: _tls_server_ecdh_cls_guess(m)
+   client_kx_msg_cls = ClientECDiffieHellmanPublic
+
+
+### Classes below are offered without any guarantee.
+### They may offer some parsing capabilities,
+### but surely won't be able to handle a proper TLS negotiation.
+### Uncomment them at your own risk.
+
+### Standard DSS-authenticated key exchange
+
+# class KX_DH_DSS(_GenericKX):
+#     descr = "DH with DSS-based certificates"
+#     server_kx_msg_cls = lambda _,m: ServerDHParams
+#     client_kx_msg_cls = ClientDiffieHellmanPublic
+
+#class KX_DHE_DSS(_GenericKX):
+#    descr = "Ephemeral DH with DSS signature"
+#    server_kx_msg_cls = lambda _,m: ServerDHParams
+#    client_kx_msg_cls = ClientDiffieHellmanPublic
+
+# class KX_DH_DSS_EXPORT(KX_DH_DSS):
+#     descr = "DH with DSS-based certificates - Export version"
+
+#class KX_DHE_DSS_EXPORT(KX_DHE_DSS):
+#    descr = "Ephemeral DH with DSS signature, export version"
+
+
+### PSK-based key exchange
+
+# class KX_PSK(_GenericKX): # RFC 4279
+#     descr = "PSK key exchange"
+#     server_kx_msg_cls = lambda _,m: ServerPSKParams
+#     client_kx_msg_cls = None
+
+# class KX_RSA_PSK(_GenericKX): # RFC 4279
+#     descr = "RSA PSK key exchange"
+#     server_kx_msg_cls = lambda _,m: ServerPSKParams
+#     client_kx_msg_cls = None
+
+# class KX_DHE_PSK(_GenericKX): # RFC 4279
+#     descr = "Ephemeral DH with PSK key exchange"
+#     server_kx_msg_cls = lambda _,m: ServerPSKParams
+#     client_kx_msg_cls = ClientDiffieHellmanPublic
+
+# class KX_ECDHE_PSK(_GenericKX): # RFC 5489
+#     descr = "Ephemeral ECDH PSK key exchange"
+#     server_kx_msg_cls = lambda _,m: _tls_server_ecdh_cls_guess(m)
+#     client_kx_msg_cls = ClientDiffieHellmanPublic
+
+
+### SRP-based key exchange
+
+#
+
+
+### Kerberos-based key exchange
+
+# class KX_KRB5(_GenericKX):
+#     descr = "Kerberos 5 key exchange"
+#     server_kx_msg_cls = lambda _,m: None  # No SKE with kerberos
+#     client_kx_msg_cls = None
+
+# class KX_KRB5_EXPORT(KX_KRB5):
+#     descr = "Kerberos 5 key exchange - Export version"
+
+
+### Unauthenticated key exchange (opportunistic encryption)
+
+# class KX_DH_anon(_GenericKX):
+#     descr = "Anonymous DH, no signatures"
+#     server_kx_msg_cls = lambda _,m: ServerDHParams
+#     client_kx_msg_cls = ClientDiffieHellmanPublic
+
+# class KX_ECDH_anon(_GenericKX):
+#     descr = "ECDH anonymous key exchange"
+#     server_kx_msg_cls = lambda _,m: _tls_server_ecdh_cls_guess(m)
+#     client_kx_msg_cls = ClientDiffieHellmanPublic
+
+# class KX_DH_anon_EXPORT(KX_DH_anon):
+#     descr = "Anonymous DH, no signatures - Export version"
+
diff --git a/scapy/layers/tls/crypto/pkcs1.py b/scapy/layers/tls/crypto/pkcs1.py
index 956268e79adaa7078a8f00da58365df2b7e7c015..e4b49c4104730f21f05acebae714e50699ac6986 100644
--- a/scapy/layers/tls/crypto/pkcs1.py
+++ b/scapy/layers/tls/crypto/pkcs1.py
@@ -5,6 +5,10 @@
 
 """
 PKCS #1 methods as defined in RFC 3447.
+
+XXX We cannot rely solely on the cryptography library, because it does not
+support our "tls" hash used with TLS 1.0. Once it is added to (or from) the
+library, most of the present module should be removed.
 """
 
 import os, popen2, tempfile
@@ -19,42 +23,14 @@ if conf.crypto_valid:
 else:
     InvalidSignature = dafault_backend = hashes = padding = None
 
+from scapy.utils import randstring, zerofree_randstring, strxor, strand
+from scapy.error import warning
+
 
 #####################################################################
 # Some helpers
 #####################################################################
 
-def _warning(m):
-    print "WARNING: %s" % m
-
-def randstring(l):
-    """
-    Returns a random string of length l (l >= 0)
-    """
-    tmp = map(lambda x: struct.pack("B", random.randrange(0, 256, 1)), [""]*l)
-    return "".join(tmp)
-
-def zerofree_randstring(l):
-    """
-    Returns a random string of length l (l >= 0) without zero in it.
-    """
-    tmp = map(lambda x: struct.pack("B", random.randrange(1, 256, 1)), [""]*l)
-    return "".join(tmp)
-
-def strxor(s1, s2):
-    """
-    Returns the binary XOR of the 2 provided strings s1 and s2. s1 and s2
-    must be of same length.
-    """
-    return "".join(map(lambda x,y:chr(ord(x)^ord(y)), s1, s2))
-
-def strand(s1, s2):
-    """
-    Returns the binary AND of the 2 provided strings s1 and s2. s1 and s2
-    must be of same length.
-    """
-    return "".join(map(lambda x,y:chr(ord(x)&ord(y)), s1, s2))
-
 # OS2IP function defined in RFC 3447 for octet string to integer conversion
 def pkcs_os2ip(x):
     """
@@ -100,24 +76,27 @@ def pkcs_ilen(n):
         i += 1
     return i
 
-# for every hash function a tuple is provided, giving access to
+
+#####################################################################
+# Hash functions
+#####################################################################
+
+# For every hash function a tuple is provided, giving access to
 # - hash output length in byte
 # - associated hash function that take data to be hashed as parameter
 #   XXX I do not provide update() at the moment.
 # - DER encoding of the leading bits of digestInfo (the hash value
 #   will be concatenated to create the complete digestInfo).
 #
-# Notes:
-# - MD4 asn.1 value should be verified. Also, as stated in
-#   PKCS#1 v2.1, MD4 should not be used.
-# - 'tls' one is the concatenation of both md5 and sha1 hashes used
-#   by SSL/TLS when signing/verifying things
+# Note that 'tls' is the concatenation of both md5 and sha1 hashes used by
+# SSL/TLS 1.0 when signing/verifying things.
 
 _hashFuncParams = {}
 if conf.crypto_valid:
 
     def _hashWrapper(hash_algo, message, backend=default_backend()):
-        digest = hashes.Hash(hash_algo, backend).update(message)
+        digest = hashes.Hash(hash_algo(), backend)
+        digest.update(message)
         return digest.finalize()
 
     _hashFuncParams = {
@@ -152,12 +131,18 @@ if conf.crypto_valid:
         }
 
 def mapHashFunc(hashStr):
+    if hashStr == "tls":
+        raise Exception("mapHashFunc is not supposed to be called on 'tls'")
     try:
-        return _hashFuncParams[hashStr][1]
+        return _hashFuncParams[hashStr][1]()
     except:
         raise Exception("Unknown hash function %s" % hashStr)
 
 
+#####################################################################
+# Some more PKCS helpers
+#####################################################################
+
 def pkcs_mgf1(mgfSeed, maskLen, h):
     """
     Implements generic MGF1 Mask Generation function as described in
@@ -179,12 +164,12 @@ def pkcs_mgf1(mgfSeed, maskLen, h):
 
     # steps are those of Appendix B.2.1
     if not _hashFuncParams.has_key(h):
-        _warning("pkcs_mgf1: invalid hash (%s) provided" % h)
+        warning("pkcs_mgf1: invalid hash (%s) provided" % h)
         return None
     hLen = _hashFuncParams[h][0]
     hFunc = _hashFuncParams[h][2]
     if maskLen > 2**32 * hLen:                               # 1)
-        _warning("pkcs_mgf1: maskLen > 2**32 * hLen")
+        warning("pkcs_mgf1: maskLen > 2**32 * hLen")
         return None
     T = ""                                                   # 2)
     maxCounter = math.ceil(float(maskLen) / float(hLen))     # 3)
@@ -222,7 +207,7 @@ def pkcs_emsa_pss_encode(M, emBits, h, mgf, sLen):
     mHash = hFunc(M)
     emLen = int(math.ceil(emBits/8.))
     if emLen < hLen + sLen + 2:                              # 3)
-        _warning("encoding error (emLen < hLen + sLen + 2)")
+        warning("encoding error (emLen < hLen + sLen + 2)")
         return None
     salt = randstring(sLen)                                  # 4)
     MPrime = '\x00'*8 + mHash + salt                         # 5)
@@ -328,7 +313,7 @@ def pkcs_emsa_pkcs1_v1_5_encode(M, emLen, h): # section 9.2 of RFC 3447
     T = hLeadingDigestInfo + H
     tLen = len(T)
     if emLen < tLen + 11:                                    # 3)
-        _warning("pkcs_emsa_pkcs1_v1_5_encode:"
+        warning("pkcs_emsa_pkcs1_v1_5_encode:"
                 "intended encoded message length too short")
         return None
     PS = '\xff'*(emLen - tLen - 3)                           # 4)
@@ -336,165 +321,166 @@ def pkcs_emsa_pkcs1_v1_5_encode(M, emLen, h): # section 9.2 of RFC 3447
     return EM                                                # 6)
 
 
-# XXX should add other pgf1 instance in a better fashion.
+#####################################################################
+# Asymmetric Cryptography wrappers
+#####################################################################
 
-def create_ca_file(anchor_list, filename):
-    """
-    Concatenate all the certificates (PEM format for the export) in
-    'anchor_list' and write the result to file 'filename'. On success
-    'filename' is returned, None otherwise.
+class _EncryptAndVerifyRSA(object):
 
-    If you are used to OpenSSL tools, this function builds a CAfile
-    that can be used for certificate and CRL check.
+    def _rsaep(self, m):
+        """
+        Internal method providing raw RSA encryption, i.e. simple modular
+        exponentiation of the given message representative 'm', a long
+        between 0 and n-1.
 
-    Also see create_temporary_ca_file().
-    """
-    try:
-        f = open(filename, "w")
-        for a in anchor_list:
-            s = a.output(fmt="PEM")
-            f.write(s)
-        f.close()
-    except:
-        return None
-    return filename
+        This is the encryption primitive RSAEP described in PKCS#1 v2.1,
+        i.e. RFC 3447 Sect. 5.1.1.
 
-def create_temporary_ca_file(anchor_list):
-    """
-    Concatenate all the certificates (PEM format for the export) in
-    'anchor_list' and write the result to file to a temporary file
-    using mkstemp() from tempfile module. On success 'filename' is
-    returned, None otherwise.
+        Input:
+           m: message representative, a long between 0 and n-1, where
+              n is the key modulus.
 
-    If you are used to OpenSSL tools, this function builds a CAfile
-    that can be used for certificate and CRL check.
-    """
-    try:
-        f, fname = tempfile.mkstemp()
-        for a in anchor_list:
-            s = a.output(fmt="PEM")
-            l = os.write(f, s)
-        os.close(f)
-    except:
-        return None
-    return fname
+        Output:
+           ciphertext representative, a long between 0 and n-1
 
-def create_temporary_ca_path(anchor_list, folder):
-    """
-    Create a CA path folder as defined in OpenSSL terminology, by
-    storing all certificates in 'anchor_list' list in PEM format
-    under provided 'folder' and then creating the associated links
-    using the hash as usually done by c_rehash.
+        Not intended to be used directly. Please, see encrypt() method.
+        """
 
-    Note that you can also include CRL in 'anchor_list'. In that
-    case, they will also be stored under 'folder' and associated
-    links will be created.
+        n = self._modulus
+        if isinstance(m, int):
+            m = long(m)
+        if (not isinstance(m, long)) or m > n-1:
+            warning("Key._rsaep() expects a long between 0 and n-1")
+            return None
 
-    In folder, the files are created with names of the form
-    0...ZZ.pem. If you provide an empty list, folder will be created
-    if it does not already exist, but that's all.
+        return pow(m, self._pubExp, n)
 
-    The number of certificates written to folder is returned on
-    success, None on error.
-    """
-    # We should probably avoid writing duplicate anchors and also
-    # check if they are all certs.
-    try:
-        if not os.path.isdir(folder):
-            os.makedirs(folder)
-    except:
-        return None
 
-    l = len(anchor_list)
-    if l == 0:
-        return None
-    fmtstr = "%%0%sd.pem" % math.ceil(math.log(l, 10))
-    i = 0
-    try:
-        for a in anchor_list:
-            fname = os.path.join(folder, fmtstr % i)
-            f = open(fname, "w")
-            s = a.output(fmt="PEM")
-            f.write(s)
-            f.close()
-            i += 1
-    except:
-        return None
+    @crypto_validator
+    def encrypt(self, m, t="pkcs", h=None, mgf=None, L=None):
+        if h == "tls" or t is None:
+            #return self.encrypt_legacy(m, t=t, h=h, mgf=mgf, L=L)
+            warning("Cannot call encrypt_legacy anymore.")
+            return None
 
-    r,w=popen2.popen2("c_rehash %s" % folder)
-    r.close(); w.close()
+        if h is not None:
+            h = mapHashFunc(h)
 
-    return l
+        if t == "pkcs":
+            pad = padding.PKCS1v15()
+        elif t == "oaep":
+            pad = padding.OAEP(mgf=mgf(h), algorithm=h, label=L)
+        else:
+            warning("Key.encrypt(): Unknown encryption type (%s) provided" % t)
+            return None
+        return self.pubkey.encrypt(m, pad)
 
 
-#####################################################################
-# Public Key Cryptography related stuff
-#####################################################################
+    ### Below are verification related methods
 
-class _EncryptAndVerifyRSA(object):
-    @crypto_validator
-    def encrypt(self, m, t=None, h=None, mgf=None, L=None):
+    def _rsavp1(self, s):
         """
-        Encrypt message 'm' using 't' encryption scheme where 't' can be:
+        Internal method providing raw RSA verification, i.e. simple modular
+        exponentiation of the given signature representative 'c', an integer
+        between 0 and n-1.
 
-        - None: the message 'm' is directly applied the RSAEP encryption
-                primitive, as described in PKCS#1 v2.1, i.e. RFC 3447
-                Sect 5.1.1. Simply put, the message undergo a modular
-                exponentiation using the public key. Additionnal method
-                parameters are just ignored.
+        This is the signature verification primitive RSAVP1 described in
+        PKCS#1 v2.1, i.e. RFC 3447 Sect. 5.2.2.
 
-        -'pkcs': the message 'm' is applied RSAES-PKCS1-V1_5-ENCRYPT encryption
-                scheme as described in section 7.2.1 of RFC 3447. In that
-                context, other parameters ('h', 'mgf', 'l') are not used.
+        Input:
+          s: signature representative, an integer between 0 and n-1,
+             where n is the key modulus.
 
-        -'oaep': the message 'm' is applied the RSAES-OAEP-ENCRYPT encryption
-                scheme, as described in PKCS#1 v2.1, i.e. RFC 3447 Sect
-                7.1.1. In that context,
+        Output:
+           message representative, an integer between 0 and n-1
 
-                o 'h' parameter provides the name of the hash method to use.
-                  Possible values are "md2", "md4", "md5", "sha1", "tls",
-                  "sha224", "sha256", "sha384" and "sha512". If none is
-                  provided, sha1 is used.
+        Not intended to be used directly. Please, see verify() method.
+        """
+        return self._rsaep(s)
 
-                o 'mgf' is the mask generation function. By default, mgf
-                  is derived from the provided hash function using the
-                  generic MGF1 (see pkcs_mgf1() for details).
-
-                o 'L' is the optional label to be associated with the message.
-                  If not provided, the default value is used, i.e the empty
-                  string. No check is done on the input limitation of the hash
-                  function regarding the size of 'L' (for instance, 2^61 - 1
-                  for SHA-1). You have been warned.
+    def _rsassa_pss_verify(self, M, S, h=None, mgf=None, sLen=None):
         """
-        if h is not None:
-            h = mapHashFunc(h)
-        if t is None: # Raw encryption
-            return self.key.encrypt(
-                m,
-                padding.AsymmetricPadding(),
-            )
-        elif t == "pkcs":
-            return self.key.encrypt(
-                m,
-                padding.PKCS1v15(),
-            )
+        Implements RSASSA-PSS-VERIFY() function described in Sect 8.1.2
+        of RFC 3447
 
-        elif t == "oaep":
-            return self.key.encrypt(
-                m,
-                padding.OAEP(
-                    mgf=mgf(h()),
-                    algorithm=h(),
-                    label=L,
-                ),
-            )
+        Input:
+           M: message whose signature is to be verified
+           S: signature to be verified, an octet string of length k, where k
+              is the length in octets of the RSA modulus n.
 
-        else:
-            _warning("Key.encrypt(): Unknown encryption type (%s) provided" % t)
-            return None
+        Output:
+           True is the signature is valid. False otherwise.
+        """
 
-    @crypto_validator
-    def verify(self, M, S, t=None, h=None, mgf=None, sLen=None):
+        # Set default parameters if not provided
+        if h is None: # By default, sha1
+            h = "sha1"
+        if not _hashFuncParams.has_key(h):
+            warning("Key._rsassa_pss_verify(): unknown hash function "
+                    "provided (%s)" % h)
+            return False
+        if mgf is None: # use mgf1 with underlying hash function
+            mgf = lambda x,y: pkcs_mgf1(x, y, h)
+        if sLen is None: # use Hash output length (A.2.3 of RFC 3447)
+            hLen = _hashFuncParams[h][0]
+            sLen = hLen
+
+        # 1) Length checking
+        modBits = self._modulusLen
+        k = modBits / 8
+        if len(S) != k:
+            return False
+
+        # 2) RSA verification
+        s = pkcs_os2ip(S)                           # 2.a)
+        m = self._rsavp1(s)                         # 2.b)
+        emLen = math.ceil((modBits - 1) / 8.)       # 2.c)
+        EM = pkcs_i2osp(m, emLen)
+
+        # 3) EMSA-PSS verification
+        result = pkcs_emsa_pss_verify(M, EM, modBits - 1, h, mgf, sLen)
+
+        return result                               # 4)
+
+
+    def _rsassa_pkcs1_v1_5_verify(self, M, S, h):
+        """
+        Implements RSASSA-PKCS1-v1_5-VERIFY() function as described in
+        Sect. 8.2.2 of RFC 3447.
+
+        Input:
+           M: message whose signature is to be verified, an octet string
+           S: signature to be verified, an octet string of length k, where
+              k is the length in octets of the RSA modulus n
+           h: hash function name (in 'md2', 'md4', 'md5', 'sha1', 'tls',
+                'sha256', 'sha384').
+
+        Output:
+           True if the signature is valid. False otherwise.
+        """
+
+        # 1) Length checking
+        k = self._modulusLen / 8
+        if len(S) != k:
+            warning("invalid signature (len(S) != k)")
+            return False
+
+        # 2) RSA verification
+        s = pkcs_os2ip(S)                           # 2.a)
+        m = self._rsavp1(s)                         # 2.b)
+        EM = pkcs_i2osp(m, k)                       # 2.c)
+
+        # 3) EMSA-PKCS1-v1_5 encoding
+        EMPrime = pkcs_emsa_pkcs1_v1_5_encode(M, k, h)
+        if EMPrime is None:
+            warning("Key._rsassa_pkcs1_v1_5_verify(): unable to encode.")
+            return False
+
+        # 4) Comparison
+        return EM == EMPrime
+
+
+    def verify_legacy(self, M, S, t=None, h=None, mgf=None, sLen=None):
         """
         Verify alleged signature 'S' is indeed the signature of message 'M'
         using 't' signature scheme where 't' can be:
@@ -531,33 +517,51 @@ class _EncryptAndVerifyRSA(object):
                   default value (the byte length of the hash value for provided
                   algorithm) by providing another one with that parameter.
         """
-        if h is not None:
-            h = mapHashFunc(h)
-
         if t is None: # RSAVP1
-            pad_inst = padding.AsymmetricPadding()
+            S = pkcs_os2ip(S)
+            n = self._modulus
+            if S > n-1:
+                warning("Signature to be verified is too long for key modulus")
+                return False
+            m = self._rsavp1(S)
+            if m is None:
+                return False
+            l = int(math.ceil(math.log(m, 2) / 8.)) # Hack
+            m = pkcs_i2osp(m, l)
+            return M == m
         elif t == "pkcs": # RSASSA-PKCS1-v1_5-VERIFY
             if h is None:
-                h = hashes.SHA1
-            pad_inst = padding.PKCS1v15()
+                h = "sha1"
+            return self._rsassa_pkcs1_v1_5_verify(M, S, h)
         elif t == "pss": # RSASSA-PSS-VERIFY
-            pad_inst = padding.PSS(mgf=mgf, salt_length=sLen)
+            return self._rsassa_pss_verify(M, S, h, mgf, sLen)
+        else:
+            warning("Key.verify(): Unknown signature type (%s) provided" % t)
+            return None
 
+    @crypto_validator
+    def verify(self, M, S, t="pkcs", h=None, mgf=None, sLen=None):
+        if h == "tls" or t is None:
+            return self.verify_legacy(M, S, t=t, h=h, mgf=mgf, sLen=sLen)
+
+        if h is not None:
+            h = mapHashFunc(h)
+
+        if t == "pkcs": # RSASSA-PKCS1-v1_5-VERIFY
+            pad = padding.PKCS1v15()
+        elif t == "pss": # RSASSA-PSS-VERIFY
+            pad = padding.PSS(mgf=mgf(h), salt_length=sLen)
         else:
-            _warning("Key.verify(): Unknown signature type (%s) provided" % t)
+            warning("Key.verify(): Unknown signature type (%s) provided" % t)
             return None
 
         try:
-            self.key.verify(
-                signature=S,
-                data=M,
-                padding=pad_inst,
-                algorithm=h(),
-            )
+            self.pubkey.verify(signature=S, data=M, padding=pad, algorithm=h)
             return True
         except InvalidSignature:
             return False
 
+
 class _DecryptAndSignRSA(object):
     ### Below are decryption related methods. Encryption ones are inherited
     ### from PubKey
@@ -581,214 +585,35 @@ class _DecryptAndSignRSA(object):
         Not intended to be used directly. Please, see decrypt() method.
         """
 
-        n = self.modulus
+        n = self._modulus
         if isinstance(c, int):
             c = long(c)
         if (not isinstance(c, long)) or c > n-1:
-            _warning("Key._rsaep() expects a long between 0 and n-1")
-            return None
-
-        return self.key.decrypt(c)
-
-
-    def _rsaes_pkcs1_v1_5_decrypt(self, C):
-        """
-        Implements RSAES-PKCS1-V1_5-DECRYPT() function described in section
-        7.2.2 of RFC 3447.
-
-        Input:
-           C: ciphertext to be decrypted, an octet string of length k, where
-              k is the length in octets of the RSA modulus n.
-
-        Output:
-           an octet string of length k at most k - 11
-
-        on error, None is returned.
-        """
-
-        # 1) Length checking
-        cLen = len(C)
-        k = self.modulusLen / 8
-        if cLen != k or k < 11:
-            _warning("Key._rsaes_pkcs1_v1_5_decrypt() decryption error "
-                    "(cLen != k or k < 11)")
+            warning("Key._rsaep() expects a long between 0 and n-1")
             return None
 
-        # 2) RSA decryption
-        c = pkcs_os2ip(C)                           # 2.a)
-        m = self._rsadp(c)                          # 2.b)
-        EM = pkcs_i2osp(m, k)                       # 2.c)
-
-        # 3) EME-PKCS1-v1_5 decoding
+        privExp = self.key.private_numbers().d
+        return pow(c, privExp, n)
 
-        # I am aware of the note at the end of 7.2.2 regarding error
-        # conditions reporting but the one provided below are for _local_
-        # debugging purposes. --arno
 
-        if EM[0] != '\x00':
-            _warning("Key._rsaes_pkcs1_v1_5_decrypt(): decryption error "
-                    "(first byte is not 0x00)")
+    def decrypt(self, C, t="pkcs", h=None, mgf=None, L=None):
+        if h == "tls" or t is None:
+            #return self.decrypt_legacy(C, t=t, h=h, mgf=mgf, L=L)
+            warning("Cannot call decrypt_legacy anymore.")
             return None
 
-        if EM[1] != '\x02':
-            _warning("Key._rsaes_pkcs1_v1_5_decrypt(): decryption error "
-                    "(second byte is not 0x02)")
-            return None
-
-        tmp = EM[2:].split('\x00', 1)
-        if len(tmp) != 2:
-            _warning("Key._rsaes_pkcs1_v1_5_decrypt(): decryption error "
-                    "(no 0x00 to separate PS from M)")
-            return None
-
-        PS, M = tmp
-        if len(PS) < 8:
-            _warning("Key._rsaes_pkcs1_v1_5_decrypt(): decryption error "
-                    "(PS is less than 8 byte long)")
-            return None
-
-        return M                                    # 4)
-
-
-    def _rsaes_oaep_decrypt(self, C, h=None, mgf=None, L=None):
-        """
-        Internal method providing RSAES-OAEP-DECRYPT as defined in Sect.
-        7.1.2 of RFC 3447. Not intended to be used directly. Please, see
-        encrypt() method for type "OAEP".
-
-
-        Input:
-           C  : ciphertext to be decrypted, an octet string of length k, where
-                k = 2*hLen + 2 (k denotes the byte length of the RSA modulus
-                and hLen the byte length of the hash function output)
-           h  : hash function name (in 'md2', 'md4', 'md5', 'sha1', 'tls',
-                'sha256', 'sha384'). 'sha1' is used if none is provided.
-           mgf: the mask generation function f : seed, maskLen -> mask
-           L  : optional label whose association with the message is to be
-                verified; the default value for L, if not provided is the empty
-                string.
-
-        Output:
-           message, an octet string of length k mLen, where mLen <= k-2*hLen-2
-
-        On error, None is returned.
-        """
-        # The steps below are the one described in Sect. 7.1.2 of RFC 3447.
-
-        # 1) Length Checking
-                                                    # 1.a) is not done
-        if h is None:
-            h = "sha1"
-        if not _hashFuncParams.has_key(h):
-            _warning("Key._rsaes_oaep_decrypt(): unknown hash function %s." % h)
-            return None
-        hLen = _hashFuncParams[h][0]
-        hFun = _hashFuncParams[h][2]
-        k = self.modulusLen / 8
-        cLen = len(C)
-        if cLen != k:                               # 1.b)
-            _warning("Key._rsaes_oaep_decrypt(): decryption error. "
-                    "(cLen != k)")
-            return None
-        if k < 2*hLen + 2:
-            _warning("Key._rsaes_oaep_decrypt(): decryption error. "
-                    "(k < 2*hLen + 2)")
-            return None
-
-        # 2) RSA decryption
-        c = pkcs_os2ip(C)                           # 2.a)
-        m = self._rsadp(c)                          # 2.b)
-        EM = pkcs_i2osp(m, k)                       # 2.c)
-
-        # 3) EME-OAEP decoding
-        if L is None:                               # 3.a)
-            L = ""
-        lHash = hFun(L)
-        Y = EM[:1]                                  # 3.b)
-        if Y != '\x00':
-            _warning("Key._rsaes_oaep_decrypt(): decryption error. "
-                    "(Y is not zero)")
-            return None
-        maskedSeed = EM[1:1+hLen]
-        maskedDB = EM[1+hLen:]
-        if mgf is None:
-            mgf = lambda x,y: pkcs_mgf1(x, y, h)
-        seedMask = mgf(maskedDB, hLen)              # 3.c)
-        seed = strxor(maskedSeed, seedMask)         # 3.d)
-        dbMask = mgf(seed, k - hLen - 1)            # 3.e)
-        DB = strxor(maskedDB, dbMask)               # 3.f)
-
-        # I am aware of the note at the end of 7.1.2 regarding error
-        # conditions reporting but the one provided below are for _local_
-        # debugging purposes. --arno
-
-        lHashPrime = DB[:hLen]                      # 3.g)
-        tmp = DB[hLen:].split('\x01', 1)
-        if len(tmp) != 2:
-            _warning("Key._rsaes_oaep_decrypt(): decryption error. "
-                    "(0x01 separator not found)")
-            return None
-        PS, M = tmp
-        if PS != '\x00'*len(PS):
-            _warning("Key._rsaes_oaep_decrypt(): decryption error. "
-                    "(invalid padding string)")
-            return None
-        if lHash != lHashPrime:
-            _warning("Key._rsaes_oaep_decrypt(): decryption error. "
-                    "(invalid hash)")
-            return None
-        return M                                    # 4)
-
-
-    def decrypt(self, C, t=None, h=None, mgf=None, L=None):
-        """
-        Decrypt ciphertext 'C' using 't' decryption scheme where 't' can be:
-
-        - None: the ciphertext 'C' is directly applied the RSADP decryption
-                primitive, as described in PKCS#1 v2.1, i.e. RFC 3447
-                Sect 5.1.2. Simply, put the message undergo a modular
-                exponentiation using the private key. Additionnal method
-                parameters are just ignored.
-
-        - 'pkcs': the ciphertext 'C' is applied RSAES-PKCS1-V1_5-DECRYPT
-                decryption scheme as described in section 7.2.2 of RFC 3447.
-                In that context, other parameters ('h', 'mgf', 'l') are not
-                used.
-
-        - 'oaep': the ciphertext 'C' is applied the RSAES-OAEP-DECRYPT
-                decryption scheme, as described in PKCS#1 v2.1, i.e. RFC 3447
-                Sect 7.1.2. In that context,
-
-                o 'h' parameter provides the name of the hash method to use.
-                  Possible values are "md2", "md4", "md5", "sha1", "tls",
-                  "sha224", "sha256", "sha384" and "sha512". If None is
-                  provided, sha1 is used by default.
-
-                o 'mgf' is the mask generation function. By default, mgf
-                  is derived from the provided hash function using the
-                  generic MGF1 (see pkcs_mgf1() for details).
-
-                o 'L' is the optional label to be associated with the
-                  message. If not provided, the default value is used, i.e
-                  the empty string. No check is done on the input limitation
-                  of the hash function regarding the size of 'L' (for
-                  instance, 2^61 - 1 for SHA-1). You have been warned.
-        """
-        if t is None:
-            C = pkcs_os2ip(C)
-            c = self._rsadp(C)
-            l = int(math.ceil(math.log(c, 2) / 8.)) # Hack
-            return pkcs_i2osp(c, l)
-
-        elif t == "pkcs":
-            return self._rsaes_pkcs1_v1_5_decrypt(C)
+        if h is not None:
+            h = mapHashFunc(h)
 
+        if t == "pkcs":
+            pad = padding.PKCS1v15()
         elif t == "oaep":
-            return self._rsaes_oaep_decrypt(C, h, mgf, L)
-
+            pad = padding.OAEP(mgf=mgf(h), algorithm=h, label=L)
         else:
-            _warning("Key.decrypt(): Unknown decryption type (%s) provided" % t)
+            warning("Key.decrypt(): Unknown decryption type (%s) provided" % t)
             return None
+        return self.key.decrypt(C, pad)
+
 
     ### Below are signature related methods.
     ### Verification methods are inherited from PubKey.
@@ -833,7 +658,7 @@ class _DecryptAndSignRSA(object):
         if h is None: # By default, sha1
             h = "sha1"
         if not _hashFuncParams.has_key(h):
-            _warning("Key._rsassa_pss_sign(): unknown hash function "
+            warning("Key._rsassa_pss_sign(): unknown hash function "
                     "provided (%s)" % h)
             return None
         if mgf is None: # use mgf1 with underlying hash function
@@ -843,11 +668,11 @@ class _DecryptAndSignRSA(object):
             sLen = hLen
 
         # 1) EMSA-PSS encoding
-        modBits = self.modulusLen
+        modBits = self._modulusLen
         k = modBits / 8
         EM = pkcs_emsa_pss_encode(M, modBits - 1, h, mgf, sLen)
         if EM is None:
-            _warning("Key._rsassa_pss_sign(): unable to encode")
+            warning("Key._rsassa_pss_sign(): unable to encode")
             return None
 
         # 2) RSA signature
@@ -873,10 +698,10 @@ class _DecryptAndSignRSA(object):
         """
 
         # 1) EMSA-PKCS1-v1_5 encoding
-        k = self.modulusLen / 8
+        k = self._modulusLen / 8
         EM = pkcs_emsa_pkcs1_v1_5_encode(M, k, h)
         if EM is None:
-            _warning("Key._rsassa_pkcs1_v1_5_sign(): unable to encode")
+            warning("Key._rsassa_pkcs1_v1_5_sign(): unable to encode")
             return None
 
         # 2) RSA signature
@@ -887,7 +712,7 @@ class _DecryptAndSignRSA(object):
         return S                                    # 3)
 
 
-    def sign(self, M, t=None, h=None, mgf=None, sLen=None):
+    def sign_legacy(self, M, t=None, h=None, mgf=None, sLen=None):
         """
         Sign message 'M' using 't' signature scheme where 't' can be:
 
@@ -920,28 +745,133 @@ class _DecryptAndSignRSA(object):
                   default value (the byte length of the hash value for provided
                   algorithm) by providing another one with that parameter.
         """
-
         if t is None: # RSASP1
             M = pkcs_os2ip(M)
-            n = self.modulus
+            n = self._modulus
             if M > n-1:
-                _warning("Message to be signed is too long for key modulus")
+                warning("Message to be signed is too long for key modulus")
                 return None
             s = self._rsasp1(M)
             if s is None:
                 return None
-            return pkcs_i2osp(s, self.modulusLen/8)
-
+            return pkcs_i2osp(s, self._modulusLen/8)
         elif t == "pkcs": # RSASSA-PKCS1-v1_5-SIGN
             if h is None:
                 h = "sha1"
             return self._rsassa_pkcs1_v1_5_sign(M, h)
-
         elif t == "pss": # RSASSA-PSS-SIGN
             return self._rsassa_pss_sign(M, h, mgf, sLen)
+        else:
+            warning("Key.sign(): Unknown signature type (%s) provided" % t)
+            return None
 
+    def sign(self, M, t="pkcs", h=None, mgf=None, sLen=None):
+        if h == "tls" or t is None:
+            return self.sign_legacy(M, t=t, h=h, mgf=mgf, sLen=sLen)
+
+        if h is not None:
+            h = mapHashFunc(h)
+
+        if t == "pkcs": # RSASSA-PKCS1-v1_5-SIGN
+            pad = padding.PKCS1v15()
+        elif t == "pss": # RSASSA-PSS-SIGN
+            pad = padding.PSS(mgf=mgf(h), salt_length=sLen)
         else:
-            _warning("Key.sign(): Unknown signature type (%s) provided" % t)
+            warning("Key.sign(): Unknown signature type (%s) provided" % t)
             return None
+        return self.key.sign(M, pad, h)
+
+
+
+#####################################################################
+# CA files helpers
+#####################################################################
 
+def create_ca_file(anchor_list, filename):
+    """
+    Concatenate all the certificates (PEM format for the export) in
+    'anchor_list' and write the result to file 'filename'. On success
+    'filename' is returned, None otherwise.
+
+    If you are used to OpenSSL tools, this function builds a CAfile
+    that can be used for certificate and CRL check.
+
+    Also see create_temporary_ca_file().
+    """
+    try:
+        f = open(filename, "w")
+        for a in anchor_list:
+            s = a.output(fmt="PEM")
+            f.write(s)
+        f.close()
+    except:
+        return None
+    return filename
+
+def create_temporary_ca_file(anchor_list):
+    """
+    Concatenate all the certificates (PEM format for the export) in
+    'anchor_list' and write the result to file to a temporary file
+    using mkstemp() from tempfile module. On success 'filename' is
+    returned, None otherwise.
+
+    If you are used to OpenSSL tools, this function builds a CAfile
+    that can be used for certificate and CRL check.
+    """
+    try:
+        f, fname = tempfile.mkstemp()
+        for a in anchor_list:
+            s = a.output(fmt="PEM")
+            l = os.write(f, s)
+        os.close(f)
+    except:
+        return None
+    return fname
+
+def create_temporary_ca_path(anchor_list, folder):
+    """
+    Create a CA path folder as defined in OpenSSL terminology, by
+    storing all certificates in 'anchor_list' list in PEM format
+    under provided 'folder' and then creating the associated links
+    using the hash as usually done by c_rehash.
+
+    Note that you can also include CRL in 'anchor_list'. In that
+    case, they will also be stored under 'folder' and associated
+    links will be created.
+
+    In folder, the files are created with names of the form
+    0...ZZ.pem. If you provide an empty list, folder will be created
+    if it does not already exist, but that's all.
+
+    The number of certificates written to folder is returned on
+    success, None on error.
+    """
+    # We should probably avoid writing duplicate anchors and also
+    # check if they are all certs.
+    try:
+        if not os.path.isdir(folder):
+            os.makedirs(folder)
+    except:
+        return None
+
+    l = len(anchor_list)
+    if l == 0:
+        return None
+    fmtstr = "%%0%sd.pem" % math.ceil(math.log(l, 10))
+    i = 0
+    try:
+        for a in anchor_list:
+            fname = os.path.join(folder, fmtstr % i)
+            f = open(fname, "w")
+            s = a.output(fmt="PEM")
+            f.write(s)
+            f.close()
+            i += 1
+    except:
+        return None
+
+    r,w=popen2.popen2("c_rehash %s" % folder)
+    r.close(); w.close()
+
+    return l
 
diff --git a/scapy/layers/tls/crypto/prf.py b/scapy/layers/tls/crypto/prf.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f93f92569074352bfb156160ec3518e16b9e70c
--- /dev/null
+++ b/scapy/layers/tls/crypto/prf.py
@@ -0,0 +1,317 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+TLS Pseudorandom Function.
+"""
+
+from scapy.error import warning
+from scapy.utils import strxor
+
+from scapy.layers.tls.crypto.hash import tls_hash_algs
+from scapy.layers.tls.crypto.h_mac import tls_hmac_algs
+
+
+### Data expansion functions
+
+def _tls_P_hash(secret, seed, req_len, hm):
+    """
+    Provides the implementation of P_hash function defined in
+    section 5 of RFC 4346 (and section 5 of RFC 5246). Two
+    parameters have been added (hm and req_len):
+
+    - secret : the key to be used. If RFC 4868 is to be believed,
+               the length must match hm.key_len. Actually,
+               python hmac takes care of formatting every key.
+    - seed : the seed to be used.
+    - req_len : the length of data to be generated by iterating
+               the specific HMAC function (hm). This prevents
+               multiple calls to the function.
+    - hm : the hmac function class to use for iteration (either
+           Hmac_MD5 or Hmac_SHA1 in TLS <= 1.1 or
+           Hmac_SHA256 or Hmac_SHA384 in TLS 1.2)
+    """
+
+    hash_len = hm.hash_alg.hash_len
+    n = (req_len + hash_len - 1) / hash_len
+
+    res = ""
+    a = hm(secret).digest(seed)  # A(1)
+
+    while n > 0:
+        res += hm(secret).digest(a + seed)
+        a = hm(secret).digest(a)
+        n -= 1
+
+    return res[:req_len]
+
+
+def _tls_P_MD5(secret, seed, req_len):
+    return _tls_P_hash(secret, seed, req_len, tls_hmac_algs["HMAC-MD5"])
+
+def _tls_P_SHA1(secret, seed, req_len):
+    return _tls_P_hash(secret, seed, req_len, tls_hmac_algs["HMAC-SHA"])
+
+def _tls_P_SHA256(secret, seed, req_len):
+    return _tls_P_hash(secret, seed, req_len, tls_hmac_algs["HMAC-SHA256"])
+
+def _tls_P_SHA384(secret, seed, req_len):
+    return _tls_P_hash(secret, seed, req_len, tls_hmac_algs["HMAC-SHA384"])
+
+def _tls_P_SHA512(secret, seed, req_len):
+    return _tls_P_hash(secret, seed, req_len, tls_hmac_algs["HMAC-SHA512"])
+
+
+### PRF functions, according to the protocol version
+
+def _ssl_PRF(secret, seed, req_len):
+    """
+    Provides the implementation of SSLv3 PRF function:
+
+     SSLv3-PRF(secret, seed) =
+        MD5(secret || SHA-1("A" || secret || seed)) ||
+        MD5(secret || SHA-1("BB" || secret || seed)) ||
+        MD5(secret || SHA-1("CCC" || secret || seed)) || ...
+
+    req_len should not be more than  26 x 16 = 416.
+
+    """
+    if req_len > 416:
+        warning("_ssl_PRF() is not expected to provide more than 416 bytes")
+        return ""
+
+    d = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
+         "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
+    res = ""
+    hash_md5 = tls_hash_algs["MD5"]
+    rounds = (req_len + hash_md5.hash_len - 1) / hash_md5.hash_len
+
+    for i in range(rounds):
+        label = d[i] * (i+1)
+        tmp = tls_hash_algs["SHA"]().digest(label + secret + seed)
+        res += tls_hash_algs["MD5"]().digest(secret + tmp)
+
+    return res[:req_len]
+
+def _tls_PRF(secret, label, seed, req_len):
+    """
+    Provides the implementation of TLS PRF function as defined in
+    section 5 of RFC 4346:
+
+    PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR
+                               P_SHA-1(S2, label + seed)
+
+    Parameters are:
+
+    - secret: the secret used by the HMAC in the 2 expansion
+              functions (S1 and S2 are the halves of this secret).
+    - label: specific label as defined in various sections of the RFC
+             depending on the use of the generated PRF keystream
+    - seed: the seed used by the expansion functions.
+    - req_len: amount of keystream to be generated
+
+    """
+
+    l = (len(secret) + 1) / 2
+    S1 = secret[:l]
+    S2 = secret[-l:]
+
+    a1 = _tls_P_MD5(S1, label+seed, req_len)
+    a2 = _tls_P_SHA1(S2, label+seed, req_len)
+
+    return strxor(a1, a2)
+
+def _tls12_SHA256PRF(secret, label, seed, req_len):
+    """
+    Provides the implementation of TLS 1.2 PRF function as
+    defined in section 5 of RFC 5246:
+
+    PRF(secret, label, seed) = P_SHA256(secret, label + seed)
+
+    Parameters are:
+
+    - secret: the secret used by the HMAC in the 2 expansion
+              functions (S1 and S2 are the halves of this secret).
+    - label: specific label as defined in various sections of the RFC
+             depending on the use of the generated PRF keystream
+    - seed: the seed used by the expansion functions.
+    - req_len: amount of keystream to be generated
+
+    """
+    return _tls_P_SHA256(secret, label+seed, req_len)
+
+def _tls12_SHA384PRF(secret, label, seed, req_len):
+    return _tls_P_SHA384(secret, label+seed, req_len)
+
+def _tls12_SHA512PRF(secret, label, seed, req_len):
+    return _tls_P_SHA512(secret, label+seed, req_len)
+
+
+class PRF(object):
+    """
+    The PRF used by SSL/TLS varies based on the version of the protocol and
+    (for TLS 1.2) possibly the Hash algorithm of the negotiated cipher suite.
+    The various uses of the PRF (key derivation, computation of verify_data,
+    computation of pre_master_secret values) for the different versions of the
+    protocol also changes. In order to abstract those elements, the common
+    _tls_PRF() object is provided. It is expected to be initialised in the
+    context of the connection state using the tls_version and the cipher suite.
+    """
+    def __init__(self, hash_name="SHA256", tls_version=0x0303):
+        self.tls_version = tls_version
+        self.hash_name = hash_name
+
+        if (tls_version == 0x0200 or        # SSLv2
+            tls_version == 0x0300):         # SSLv3
+            self.prf = _ssl_PRF
+        elif (tls_version == 0x0301 or      # TLS 1.0
+              tls_version == 0x0302):       # TLS 1.1
+            self.prf = _tls_PRF
+        elif tls_version == 0x0303:         # TLS 1.2
+            if hash_name == "SHA384":
+                self.prf = _tls12_SHA384PRF
+            elif hash_name == "SHA512":
+                self.prf = _tls12_SHA512PRF
+            else:
+                self.prf = _tls12_SHA256PRF
+        else:
+            warning("Unknown TLS version")
+
+    def compute_master_secret(self, pre_master_secret,
+                              client_random, server_random):
+        """
+        Return the 48-byte master_secret, computed from pre_master_secret,
+        client_random and server_random. See RFC 5246, section 6.3.
+        """
+        seed = client_random + server_random
+        if self.tls_version <= 0x0300:
+            return self.prf(pre_master_secret, seed, 48)
+        else:
+            return self.prf(pre_master_secret, "master secret", seed, 48)
+
+    def derive_key_block(self, master_secret, server_random,
+                         client_random, req_len):
+        """
+        Perform the derivation of master_secret into a key_block of req_len
+        requested length. See RFC 5246, section 6.3.
+        """
+        seed = server_random + client_random
+        if self.tls_version <= 0x0300:
+            return self.prf(master_secret, seed, req_len)
+        else:
+            return self.prf(master_secret, "key expansion", seed, req_len)
+
+    def compute_verify_data(self, con_end, read_or_write,
+                            handshake_msg, master_secret):
+        """
+        Return verify_data based on handshake messages, connection end,
+        master secret, and read_or_write position. See RFC 5246, section 7.4.9.
+
+        Every TLS 1.2 cipher suite has a verify_data of length 12. Note also:
+        "This PRF with the SHA-256 hash function is used for all cipher
+         suites defined in this document and in TLS documents published
+         prior to this document when TLS 1.2 is negotiated."
+        Cipher suites using SHA-384 were defined later on.
+        """
+        if self.tls_version <= 0x0300:
+
+            if read_or_write == "write":
+                d = {"client": "CLNT", "server": "SRVR"}
+            else:
+                d = {"client": "SRVR", "server": "CLNT"}
+            label = d[con_end]
+
+            sslv3_md5_pad1 = "\x36"*48
+            sslv3_md5_pad2 = "\x5c"*48
+            sslv3_sha1_pad1 = "\x36"*40
+            sslv3_sha1_pad2 = "\x5c"*40
+
+            md5 = tls_hash_algs["MD5"]()
+            sha1 = tls_hash_algs["SHA"]()
+
+            md5_hash = md5.digest(master_secret + sslv3_md5_pad2 +
+                                  md5.digest(handshake_msg + label +
+                                             master_secret + sslv3_md5_pad1))
+            sha1_hash = sha1.digest(master_secret + sslv3_sha1_pad2 +
+                                    sha1.digest(handshake_msg + label +
+                                                master_secret + sslv3_sha1_pad1))
+            verify_data = md5_hash + sha1_hash
+
+        else:
+
+            if read_or_write == "write":
+                d = {"client": "client", "server": "server"}
+            else:
+                d = {"client": "server", "server": "client"}
+            label = d[con_end] + " finished"
+
+            if self.tls_version <= 0x0302:
+                s1 = tls_hash_algs["MD5"]().digest(handshake_msg)
+                s2 = tls_hash_algs["SHA"]().digest(handshake_msg)
+                verify_data = self.prf(master_secret, label, s1 + s2, 12)
+            else:
+                if self.hash_name in ["MD5", "SHA"]:
+                    h = tls_hash_algs["SHA256"]()
+                else:
+                    h = tls_hash_algs[self.hash_name]()
+                s = h.digest(handshake_msg)
+                verify_data = self.prf(master_secret, label, s, 12)
+
+        return verify_data
+
+    def postprocess_key_for_export(self, key, client_random, server_random,
+                                   con_end, read_or_write, req_len):
+        """
+        Postprocess cipher key for EXPORT ciphersuite, i.e. weakens it.
+        An export key generation example is given in section 6.3.1 of RFC 2246.
+        See also page 86 of EKR's book.
+        """
+        s = con_end + read_or_write
+        s = (s == "clientwrite" or s == "serverread")
+
+        if self.tls_version == 0x0300:
+            if s:
+                tbh = key + client_random + server_random
+            else:
+                tbh = key + server_random + client_random
+            export_key = tls_hash_algs["MD5"]().digest(tbh)[:req_len]
+        else:
+            if s:
+                tag = "client write key"
+            else:
+                tag = "server write key"
+            export_key = self.prf(key,
+                                  tag,
+                                  client_random + server_random,
+                                  req_len)
+        return export_key
+
+    def generate_iv_for_export(self, client_random, server_random,
+                               con_end, read_or_write, req_len):
+        """
+        Generate IV for EXPORT ciphersuite, i.e. weakens it.
+        An export IV generation example is given in section 6.3.1 of RFC 2246.
+        See also page 86 of EKR's book.
+        """
+        s = con_end + read_or_write
+        s = (s == "clientwrite" or s == "serverread")
+
+        if self.tls_version == 0x0300:
+            if s:
+                tbh = client_random + server_random
+            else:
+                tbh = server_random + client_random
+            iv = tls_hash_algs["MD5"]().digest(tbh)[:req_len]
+        else:
+            iv_block = self.prf("",
+                                "IV block",
+                                client_random + server_random,
+                                2*req_len)
+            if s:
+                iv = iv_block[:req_len]
+            else:
+                iv = iv_block[req_len:]
+        return iv
+
diff --git a/scapy/layers/tls/crypto/suites.py b/scapy/layers/tls/crypto/suites.py
new file mode 100644
index 0000000000000000000000000000000000000000..7605a736e88ac40910ecc151095e7b9952d1f1a0
--- /dev/null
+++ b/scapy/layers/tls/crypto/suites.py
@@ -0,0 +1,971 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+TLS cipher suites.
+
+A comprehensive list of specified cipher suites can be consulted at:
+https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml
+"""
+
+from scapy.layers.tls.crypto.kx_algs import tls_kx_algs
+from scapy.layers.tls.crypto.hash import tls_hash_algs
+from scapy.layers.tls.crypto.h_mac import tls_hmac_algs
+from scapy.layers.tls.crypto.ciphers import tls_cipher_algs
+
+
+def get_algs_from_ciphersuite_name(ciphersuite_name):
+    """
+    Return the 3-tuple made of the Key Exchange Algorithm class, the Cipher
+    class and the HMAC class, through the parsing of the ciphersuite name.
+    """
+    s = ciphersuite_name[4:]
+
+    kx_name, s = s.split("_WITH_")
+    kx_alg = tls_kx_algs.get(kx_name)
+
+    if s.endswith("CCM") or s.endswith("CCM_8"):
+
+        hash_alg = tls_hash_algs.get("SHA256")
+        cipher_alg = tls_cipher_algs.get(s)
+        hmac_alg = None
+
+    else:
+
+        hash_name = s.split('_')[-1]
+        hash_alg = tls_hash_algs.get(hash_name)
+
+        cipher_name = s[:-(len(hash_name) + 1)]
+        cipher_alg = tls_cipher_algs.get(cipher_name)
+
+        hmac_alg = None
+        if cipher_alg is not None and cipher_alg.type != "aead":
+            hmac_name = "HMAC-%s" % hash_name
+            hmac_alg = tls_hmac_algs.get(hmac_name)
+
+    return kx_alg, cipher_alg, hmac_alg, hash_alg
+
+
+_tls_cipher_suites = {}
+_tls_cipher_suites_cls = {}
+
+class _GenericCipherSuiteMetaclass(type):
+    """
+    Cipher suite classes are automatically registered through this metaclass.
+    Their name attribute equates their respective class name.
+
+    We also pre-compute every expected length of the key block to be generated,
+    which may vary according to the current tls_version. The default is set to
+    the TLS 1.2 length, and the value should be set at class instantiation.
+
+    Regarding the AEAD cipher suites, note that the 'hmac_alg' attribute will
+    be set to None. Yet, we always need a 'hash_alg' for the PRF.
+
+    Also, if pycrypto 2.7a is not installed, there will be no AES.GCM nor
+    AES.CCM support, so the 'usable' attribute will be set to False.
+    """
+    def __new__(cls, cs_name, bases, dct):
+        cs_val = dct.get("val")
+
+        if cs_name != "_GenericCipherSuite":
+            kx, c, hm, h = get_algs_from_ciphersuite_name(cs_name)
+
+            if (kx is None or c is None or h is None):
+                dct["usable"] = False
+            else:
+                dct["usable"] = True
+                dct["name"] = cs_name
+                dct["kx_alg"] = kx
+                dct["cipher_alg"] = c
+                dct["hmac_alg"] = hm
+                dct["hash_alg"] = h
+
+                kb_len = 2*c.key_len
+
+                if c.type == "stream" or c.type == "block":
+                    kb_len += 2*hm.key_len
+
+                kb_len_v1_0 = kb_len
+                if c.type == "block":
+                    kb_len_v1_0 += 2*c.block_size
+                    # no explicit IVs added for TLS 1.1+
+                elif c.type == "aead":
+                    kb_len_v1_0 += 2*c.salt_len
+                    kb_len += 2*c.salt_len
+
+                dct["_key_block_len_v1_0"] = kb_len_v1_0
+                dct["key_block_len"] = kb_len
+
+            _tls_cipher_suites[cs_val] = cs_name
+        the_class = super(_GenericCipherSuiteMetaclass, cls).__new__(cls,
+                                                                    cs_name,
+                                                                    bases,
+                                                                    dct)
+        if cs_name != "_GenericCipherSuite":
+            _tls_cipher_suites_cls[cs_val] = the_class
+        return the_class
+
+
+class _GenericCipherSuite(object):
+    __metaclass__ = _GenericCipherSuiteMetaclass
+
+    def __init__(self, tls_version=0x0303):
+        """
+        Most of the attributes are fixed and have already been set by the
+        metaclass, but we still have to provide tls_version differentiation.
+
+        For now, the key_block_len remains the only application if this.
+        Indeed for TLS 1.1+, when using a block cipher, there are no implicit
+        IVs derived from the master secret. Note that an overlong key_block_len
+        would not affect the secret generation (the trailing bytes would
+        simply be discarded), but we still provide this for completeness.
+        """
+        super(_GenericCipherSuite, self).__init__()
+        if tls_version <= 0x301:
+            self.key_block_len = self._key_block_len_v1_0
+
+
+class TLS_NULL_WITH_NULL_NULL(_GenericCipherSuite):
+    val = 0x0000
+
+class TLS_RSA_WITH_NULL_MD5(_GenericCipherSuite):
+    val = 0x0001
+
+class TLS_RSA_WITH_NULL_SHA(_GenericCipherSuite):
+    val = 0x0002
+
+class TLS_RSA_EXPORT_WITH_RC4_40_MD5(_GenericCipherSuite):
+    val = 0x0003
+
+class TLS_RSA_WITH_RC4_128_MD5(_GenericCipherSuite):
+    val = 0x0004
+
+class TLS_RSA_WITH_RC4_128_SHA(_GenericCipherSuite):
+    val = 0x0005
+
+class TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5(_GenericCipherSuite):
+    val = 0x0006
+
+class TLS_RSA_WITH_IDEA_CBC_SHA(_GenericCipherSuite):
+    val = 0x0007
+
+class TLS_RSA_EXPORT_WITH_DES40_CBC_SHA(_GenericCipherSuite):
+    val = 0x0008
+
+class TLS_RSA_WITH_DES_CBC_SHA(_GenericCipherSuite):
+    val = 0x0009
+
+class TLS_RSA_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0x000A
+
+class TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA(_GenericCipherSuite):
+    val = 0x000B
+
+class TLS_DH_DSS_WITH_DES_CBC_SHA(_GenericCipherSuite):
+    val = 0x000C
+
+class TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0x000D
+
+class TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA(_GenericCipherSuite):
+    val = 0x000E
+
+class TLS_DH_RSA_WITH_DES_CBC_SHA(_GenericCipherSuite):
+    val = 0x000F
+
+class TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0x0010
+
+class TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA(_GenericCipherSuite):
+    val = 0x0011
+
+class TLS_DHE_DSS_WITH_DES_CBC_SHA(_GenericCipherSuite):
+    val = 0x0012
+
+class TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0x0013
+
+class TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA(_GenericCipherSuite):
+    val = 0x0014
+
+class TLS_DHE_RSA_WITH_DES_CBC_SHA(_GenericCipherSuite):
+    val = 0x0015
+
+class TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0x0016
+
+class TLS_DH_anon_EXPORT_WITH_RC4_40_MD5(_GenericCipherSuite):
+    val = 0x0017
+
+class TLS_DH_anon_WITH_RC4_128_MD5(_GenericCipherSuite):
+    val = 0x0018
+
+class TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA(_GenericCipherSuite):
+    val = 0x0019
+
+class TLS_DH_anon_WITH_DES_CBC_SHA(_GenericCipherSuite):
+    val = 0x001A
+
+class TLS_DH_anon_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0x001B
+
+class TLS_KRB5_WITH_DES_CBC_SHA(_GenericCipherSuite):
+    val = 0x001E
+
+class TLS_KRB5_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0x001F
+
+class TLS_KRB5_WITH_RC4_128_SHA(_GenericCipherSuite):
+    val = 0x0020
+
+class TLS_KRB5_WITH_IDEA_CBC_SHA(_GenericCipherSuite):
+    val = 0x0021
+
+class TLS_KRB5_WITH_DES_CBC_MD5(_GenericCipherSuite):
+    val = 0x0022
+
+class TLS_KRB5_WITH_3DES_EDE_CBC_MD5(_GenericCipherSuite):
+    val = 0x0023
+
+class TLS_KRB5_WITH_RC4_128_MD5(_GenericCipherSuite):
+    val = 0x0024
+
+class TLS_KRB5_WITH_IDEA_CBC_MD5(_GenericCipherSuite):
+    val = 0x0025
+
+class TLS_KRB5_EXPORT_WITH_DES40_CBC_SHA(_GenericCipherSuite):
+    val = 0x0026
+
+class TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA(_GenericCipherSuite):
+    val = 0x0027
+
+class TLS_KRB5_EXPORT_WITH_RC4_40_SHA(_GenericCipherSuite):
+    val = 0x0028
+
+class TLS_KRB5_EXPORT_WITH_DES40_CBC_MD5(_GenericCipherSuite):
+    val = 0x0029
+
+class TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5(_GenericCipherSuite):
+    val = 0x002A
+
+class TLS_KRB5_EXPORT_WITH_RC4_40_MD5(_GenericCipherSuite):
+    val = 0x002B
+
+class TLS_PSK_WITH_NULL_SHA(_GenericCipherSuite):
+    val = 0x002C
+
+class TLS_DHE_PSK_WITH_NULL_SHA(_GenericCipherSuite):
+    val = 0x002D
+
+class TLS_RSA_PSK_WITH_NULL_SHA(_GenericCipherSuite):
+    val = 0x002E
+
+class TLS_RSA_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0x002F
+
+class TLS_DH_DSS_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0x0030
+
+class TLS_DH_RSA_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0x0031
+
+class TLS_DHE_DSS_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0x0032
+
+class TLS_DHE_RSA_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0x0033
+
+class TLS_DH_anon_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0x0034
+
+class TLS_RSA_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0x0035
+
+class TLS_DH_DSS_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0x0036
+
+class TLS_DH_RSA_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0x0037
+
+class TLS_DHE_DSS_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0x0038
+
+class TLS_DHE_RSA_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0x0039
+
+class TLS_DH_anon_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0x003A
+
+class TLS_RSA_WITH_NULL_SHA256(_GenericCipherSuite):
+    val = 0x003B
+
+class TLS_RSA_WITH_AES_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0x003C
+
+class TLS_RSA_WITH_AES_256_CBC_SHA256(_GenericCipherSuite):
+    val = 0x003D
+
+class TLS_DH_DSS_WITH_AES_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0x003E
+
+class TLS_DH_RSA_WITH_AES_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0x003F
+
+class TLS_DHE_DSS_WITH_AES_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0x0040
+
+class TLS_RSA_WITH_CAMELLIA_128_CBC_SHA(_GenericCipherSuite):
+    val = 0x0041
+
+class TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA(_GenericCipherSuite):
+    val = 0x0042
+
+class TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA(_GenericCipherSuite):
+    val = 0x0043
+
+class TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA(_GenericCipherSuite):
+    val = 0x0044
+
+class TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA(_GenericCipherSuite):
+    val = 0x0045
+
+class TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA(_GenericCipherSuite):
+    val = 0x0046
+
+class TLS_DHE_RSA_WITH_AES_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0x0067
+
+class TLS_DH_DSS_WITH_AES_256_CBC_SHA256(_GenericCipherSuite):
+    val = 0x0068
+
+class TLS_DH_RSA_WITH_AES_256_CBC_SHA256(_GenericCipherSuite):
+    val = 0x0069
+
+class TLS_DHE_DSS_WITH_AES_256_CBC_SHA256(_GenericCipherSuite):
+    val = 0x006A
+
+class TLS_DHE_RSA_WITH_AES_256_CBC_SHA256(_GenericCipherSuite):
+    val = 0x006B
+
+class TLS_DH_anon_WITH_AES_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0x006C
+
+class TLS_DH_anon_WITH_AES_256_CBC_SHA256(_GenericCipherSuite):
+    val = 0x006D
+
+class TLS_RSA_WITH_CAMELLIA_256_CBC_SHA(_GenericCipherSuite):
+    val = 0x0084
+
+class TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA(_GenericCipherSuite):
+    val = 0x0085
+
+class TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA(_GenericCipherSuite):
+    val = 0x0086
+
+class TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA(_GenericCipherSuite):
+    val = 0x0087
+
+class TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA(_GenericCipherSuite):
+    val = 0x0088
+
+class TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA(_GenericCipherSuite):
+    val = 0x0089
+
+class TLS_PSK_WITH_RC4_128_SHA(_GenericCipherSuite):
+    val = 0x008A
+
+class TLS_PSK_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0x008B
+
+class TLS_PSK_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0x008C
+
+class TLS_PSK_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0x008D
+
+class TLS_DHE_PSK_WITH_RC4_128_SHA(_GenericCipherSuite):
+    val = 0x008E
+
+class TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0x008F
+
+class TLS_DHE_PSK_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0x0090
+
+class TLS_DHE_PSK_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0x0091
+
+class TLS_RSA_PSK_WITH_RC4_128_SHA(_GenericCipherSuite):
+    val = 0x0092
+
+class TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0x0093
+
+class TLS_RSA_PSK_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0x0094
+
+class TLS_RSA_PSK_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0x0095
+
+class TLS_RSA_WITH_SEED_CBC_SHA(_GenericCipherSuite):
+    val = 0x0096
+
+class TLS_DH_DSS_WITH_SEED_CBC_SHA(_GenericCipherSuite):
+    val = 0x0097
+
+class TLS_DH_RSA_WITH_SEED_CBC_SHA(_GenericCipherSuite):
+    val = 0x0098
+
+class TLS_DHE_DSS_WITH_SEED_CBC_SHA(_GenericCipherSuite):
+    val = 0x0099
+
+class TLS_DHE_RSA_WITH_SEED_CBC_SHA(_GenericCipherSuite):
+    val = 0x009A
+
+class TLS_DH_anon_WITH_SEED_CBC_SHA(_GenericCipherSuite):
+    val = 0x009B
+
+class TLS_RSA_WITH_AES_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0x009C
+
+class TLS_RSA_WITH_AES_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0x009D
+
+class TLS_DHE_RSA_WITH_AES_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0x009E
+
+class TLS_DHE_RSA_WITH_AES_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0x009F
+
+class TLS_DH_RSA_WITH_AES_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0x00A0
+
+class TLS_DH_RSA_WITH_AES_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0x00A1
+
+class TLS_DHE_DSS_WITH_AES_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0x00A2
+
+class TLS_DHE_DSS_WITH_AES_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0x00A3
+
+class TLS_DH_DSS_WITH_AES_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0x00A4
+
+class TLS_DH_DSS_WITH_AES_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0x00A5
+
+class TLS_DH_anon_WITH_AES_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0x00A6
+
+class TLS_DH_anon_WITH_AES_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0x00A7
+
+class TLS_PSK_WITH_AES_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0x00A8
+
+class TLS_PSK_WITH_AES_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0x00A9
+
+class TLS_DHE_PSK_WITH_AES_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0x00AA
+
+class TLS_DHE_PSK_WITH_AES_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0x00AB
+
+class TLS_RSA_PSK_WITH_AES_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0x00AC
+
+class TLS_RSA_PSK_WITH_AES_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0x00AD
+
+class TLS_PSK_WITH_AES_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0x00AE
+
+class TLS_PSK_WITH_AES_256_CBC_SHA384(_GenericCipherSuite):
+    val = 0x00AF
+
+class TLS_PSK_WITH_NULL_SHA256(_GenericCipherSuite):
+    val = 0x00B0
+
+class TLS_PSK_WITH_NULL_SHA384(_GenericCipherSuite):
+    val = 0x00B1
+
+class TLS_DHE_PSK_WITH_AES_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0x00B2
+
+class TLS_DHE_PSK_WITH_AES_256_CBC_SHA384(_GenericCipherSuite):
+    val = 0x00B3
+
+class TLS_DHE_PSK_WITH_NULL_SHA256(_GenericCipherSuite):
+    val = 0x00B4
+
+class TLS_DHE_PSK_WITH_NULL_SHA384(_GenericCipherSuite):
+    val = 0x00B5
+
+class TLS_RSA_PSK_WITH_AES_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0x00B6
+
+class TLS_RSA_PSK_WITH_AES_256_CBC_SHA384(_GenericCipherSuite):
+    val = 0x00B7
+
+class TLS_RSA_PSK_WITH_NULL_SHA256(_GenericCipherSuite):
+    val = 0x00B8
+
+class TLS_RSA_PSK_WITH_NULL_SHA384(_GenericCipherSuite):
+    val = 0x00B9
+
+class TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0x00BA
+
+class TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0x00BB
+
+class TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0x00BC
+
+class TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0x00BD
+
+class TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0x00BE
+
+class TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0x00BF
+
+class TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256(_GenericCipherSuite):
+    val = 0x00C0
+
+class TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256(_GenericCipherSuite):
+    val = 0x00C1
+
+class TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256(_GenericCipherSuite):
+    val = 0x00C2
+
+class TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256(_GenericCipherSuite):
+    val = 0x00C3
+
+class TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256(_GenericCipherSuite):
+    val = 0x00C4
+
+class TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256(_GenericCipherSuite):
+    val = 0x00C5
+
+#class TLS_EMPTY_RENEGOTIATION_INFO_CSV(_GenericCipherSuite):
+#    val = 0x00FF
+
+#class TLS_FALLBACK_SCSV(_GenericCipherSuite):
+#    val = 0x5600
+
+class TLS_ECDH_ECDSA_WITH_NULL_SHA(_GenericCipherSuite):
+    val = 0xC001
+
+class TLS_ECDH_ECDSA_WITH_RC4_128_SHA(_GenericCipherSuite):
+    val = 0xC002
+
+class TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0xC003
+
+class TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0xC004
+
+class TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0xC005
+
+class TLS_ECDHE_ECDSA_WITH_NULL_SHA(_GenericCipherSuite):
+    val = 0xC006
+
+class TLS_ECDHE_ECDSA_WITH_RC4_128_SHA(_GenericCipherSuite):
+    val = 0xC007
+
+class TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0xC008
+
+class TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0xC009
+
+class TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0xC00A
+
+class TLS_ECDH_RSA_WITH_NULL_SHA(_GenericCipherSuite):
+    val = 0xC00B
+
+class TLS_ECDH_RSA_WITH_RC4_128_SHA(_GenericCipherSuite):
+    val = 0xC00C
+
+class TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0xC00D
+
+class TLS_ECDH_RSA_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0xC00E
+
+class TLS_ECDH_RSA_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0xC00F
+
+class TLS_ECDHE_RSA_WITH_NULL_SHA(_GenericCipherSuite):
+    val = 0xC010
+
+class TLS_ECDHE_RSA_WITH_RC4_128_SHA(_GenericCipherSuite):
+    val = 0xC011
+
+class TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0xC012
+
+class TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0xC013
+
+class TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0xC014
+
+class TLS_ECDH_anon_WITH_NULL_SHA(_GenericCipherSuite):
+    val = 0xC015
+
+class TLS_ECDH_anon_WITH_RC4_128_SHA(_GenericCipherSuite):
+    val = 0xC016
+
+class TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0xC017
+
+class TLS_ECDH_anon_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0xC018
+
+class TLS_ECDH_anon_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0xC019
+
+class TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0xC01A
+
+class TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0xC01B
+
+class TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0xC01C
+
+class TLS_SRP_SHA_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0xC01D
+
+class TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0xC01E
+
+class TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0xC01F
+
+class TLS_SRP_SHA_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0xC020
+
+class TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0xC021
+
+class TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0xC022
+
+class TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0xC023
+
+class TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384(_GenericCipherSuite):
+    val = 0xC024
+
+class TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0xC025
+
+class TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384(_GenericCipherSuite):
+    val = 0xC026
+
+class TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0xC027
+
+class TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384(_GenericCipherSuite):
+    val = 0xC028
+
+class TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0xC029
+
+class TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384(_GenericCipherSuite):
+    val = 0xC02A
+
+class TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0xC02B
+
+class TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0xC02C
+
+class TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0xC02D
+
+class TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0xC02E
+
+class TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0xC02F
+
+class TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0xC030
+
+class TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0xC031
+
+class TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0xC032
+
+class TLS_ECDHE_PSK_WITH_RC4_128_SHA(_GenericCipherSuite):
+    val = 0xC033
+
+class TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA(_GenericCipherSuite):
+    val = 0xC034
+
+class TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA(_GenericCipherSuite):
+    val = 0xC035
+
+class TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA(_GenericCipherSuite):
+    val = 0xC036
+
+class TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0xC037
+
+class TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384(_GenericCipherSuite):
+    val = 0xC038
+
+class TLS_ECDHE_PSK_WITH_NULL_SHA(_GenericCipherSuite):
+    val = 0xC039
+
+class TLS_ECDHE_PSK_WITH_NULL_SHA256(_GenericCipherSuite):
+    val = 0xC03A
+
+class TLS_ECDHE_PSK_WITH_NULL_SHA384(_GenericCipherSuite):
+    val = 0xC03B
+
+# suites 0xC03C-C071 use ARIA
+
+class TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0xC072
+
+class TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384(_GenericCipherSuite):
+    val = 0xC073
+
+class TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0xC074
+
+class TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384(_GenericCipherSuite):
+    val = 0xC075
+
+class TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0xC076
+
+class TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384(_GenericCipherSuite):
+    val = 0xC077
+
+class TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0xC078
+
+class TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384(_GenericCipherSuite):
+    val = 0xC079
+
+class TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0xC07A
+
+class TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0xC07B
+
+class TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0xC07C
+
+class TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0xC07D
+
+class TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0xC07E
+
+class TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0xC07F
+
+class TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0xC080
+
+class TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0xC081
+
+class TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0xC082
+
+class TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0xC083
+
+class TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0xC084
+
+class TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0xC085
+
+class TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0xC086
+
+class TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0xC087
+
+class TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0xC088
+
+class TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0xC089
+
+class TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0xC08A
+
+class TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0xC08B
+
+class TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0xC08C
+
+class TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0xC08D
+
+class TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0xC08E
+
+class TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0xC08F
+
+class TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0xC090
+
+class TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0xC091
+
+class TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256(_GenericCipherSuite):
+    val = 0xC092
+
+class TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384(_GenericCipherSuite):
+    val = 0xC093
+
+class TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0xC094
+
+class TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384(_GenericCipherSuite):
+    val = 0xC095
+
+class TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0xC096
+
+class TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384(_GenericCipherSuite):
+    val = 0xC097
+
+class TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0xC098
+
+class TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384(_GenericCipherSuite):
+    val = 0xC099
+
+class TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256(_GenericCipherSuite):
+    val = 0xC09A
+
+class TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384(_GenericCipherSuite):
+    val = 0xC09B
+
+class TLS_RSA_WITH_AES_128_CCM(_GenericCipherSuite):
+    val = 0xC09C
+
+class TLS_RSA_WITH_AES_256_CCM(_GenericCipherSuite):
+    val = 0xC09D
+
+class TLS_DHE_RSA_WITH_AES_128_CCM(_GenericCipherSuite):
+    val = 0xC09E
+
+class TLS_DHE_RSA_WITH_AES_256_CCM(_GenericCipherSuite):
+    val = 0xC09F
+
+class TLS_RSA_WITH_AES_128_CCM_8(_GenericCipherSuite):
+    val = 0xC0A0
+
+class TLS_RSA_WITH_AES_256_CCM_8(_GenericCipherSuite):
+    val = 0xC0A1
+
+class TLS_DHE_RSA_WITH_AES_128_CCM_8(_GenericCipherSuite):
+    val = 0xC0A2
+
+class TLS_DHE_RSA_WITH_AES_256_CCM_8(_GenericCipherSuite):
+    val = 0xC0A3
+
+class TLS_PSK_WITH_AES_128_CCM(_GenericCipherSuite):
+    val = 0xC0A4
+
+class TLS_PSK_WITH_AES_256_CCM(_GenericCipherSuite):
+    val = 0xC0A5
+
+class TLS_DHE_PSK_WITH_AES_128_CCM(_GenericCipherSuite):
+    val = 0xC0A6
+
+class TLS_DHE_PSK_WITH_AES_256_CCM(_GenericCipherSuite):
+    val = 0xC0A7
+
+class TLS_PSK_WITH_AES_128_CCM_8(_GenericCipherSuite):
+    val = 0xC0A8
+
+class TLS_PSK_WITH_AES_256_CCM_8(_GenericCipherSuite):
+    val = 0xC0A9
+
+class TLS_DHE_PSK_WITH_AES_128_CCM_8(_GenericCipherSuite):
+    val = 0xC0AA
+
+class TLS_DHE_PSK_WITH_AES_256_CCM_8(_GenericCipherSuite):
+    val = 0xC0AB
+
+class TLS_ECDHE_ECDSA_WITH_AES_128_CCM(_GenericCipherSuite):
+    val = 0xC0AC
+
+class TLS_ECDHE_ECDSA_WITH_AES_256_CCM(_GenericCipherSuite):
+    val = 0xC0AD
+
+class TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8(_GenericCipherSuite):
+    val = 0xC0AE
+
+class TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8(_GenericCipherSuite):
+    val = 0xC0AF
+
+#class TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256(_GenericCipherSuite):
+#    val = 0xCCA8
+#
+#class TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256(_GenericCipherSuite):
+#    val = 0xCCA9
+#
+#class TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256(_GenericCipherSuite):
+#    val = 0xCCAA
+#
+#class TLS_PSK_WITH_CHACHA20_POLY1305_SHA256(_GenericCipherSuite):
+#    val = 0xCCAB
+#
+#class TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256(_GenericCipherSuite):
+#    val = 0xCCAC
+#
+#class TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256(_GenericCipherSuite):
+#    val = 0xCCAD
+#
+#class TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256(_GenericCipherSuite):
+#    val = 0xCCAE
+
+
+_tls_cipher_suites[0x00ff] = "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"
+_tls_cipher_suites[0x5600] = "TLS_FALLBACK_SCSV"
+
+
+def get_usable_ciphersuites(l, kx):
+    """
+    From a list of proposed ciphersuites, this function returns a list of
+    usable cipher suites, i.e. for which key exchange, cipher and hash
+    algorithms are known to be implemented and usable in current version of the
+    TLS extension. The order of the cipher suites in the list returned by the
+    function matches the one of the proposal.
+    """
+    res = []
+    for c in l:
+        if _tls_cipher_suites_cls.has_key(c):
+            ciph = _tls_cipher_suites_cls[c]
+            if ciph.usable:
+                #XXX select among RSA and ECDSA cipher suites
+                # according to the key(s) the server was given
+                if kx in ciph.kx_alg.name:
+                    res.append(c)
+    return res
+
diff --git a/scapy/layers/tls/handshake.py b/scapy/layers/tls/handshake.py
new file mode 100644
index 0000000000000000000000000000000000000000..5ee9aaeaa6bc99ff2c58f7082800675041407ac7
--- /dev/null
+++ b/scapy/layers/tls/handshake.py
@@ -0,0 +1,1471 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+TLS handshake fields & logic.
+
+This module covers the handshake TLS subprotocol, except for the key exchange
+mechanisms which are addressed with keyexchange.py.
+"""
+
+import math
+
+from scapy.error import warning
+from scapy.fields import *
+from scapy.packet import Packet, Raw, Padding
+from scapy.utils import repr_hex
+from scapy.layers.x509 import X509_Extensions, OCSP_Response
+from scapy.layers.tls.cert import Cert, PrivKey, PubKey
+from scapy.layers.tls.basefields import _tls_version, _TLSVersionField
+from scapy.layers.tls.keyexchange import (_tls_named_curves, _tls_hash_sig,
+                                          _TLSSignature, _TLSServerParamsField,
+                                          _TLSSignatureField, ServerRSAParams,
+                                          SigAndHashAlgsField,
+                                          SigAndHashAlgsLenField)
+from scapy.layers.tls.session import (_GenericTLSSessionInheritance,
+                                      writeConnState,
+                                      readConnState)
+from scapy.layers.tls.crypto.compression import (_tls_compression_algs,
+                                                 _tls_compression_algs_cls,
+                                                 _GenericComp,
+                                                 _GenericCompMetaclass)
+from scapy.layers.tls.crypto.suites import (_tls_cipher_suites,
+                                            _tls_cipher_suites_cls,
+                                            _GenericCipherSuite,
+                                            _GenericCipherSuiteMetaclass,
+                                            TLS_DHE_RSA_WITH_AES_128_CBC_SHA)
+
+
+###############################################################################
+### Generic TLS Handshake message                                           ###
+###############################################################################
+
+_tls_handshake_type = { 0: "hello_request",         1: "client_hello",
+                        2: "server_hello",          3: "hello_verify_request",
+                        4: "session_ticket",        11: "certificate",
+                        12: "server_key_exchange",  13: "certificate_request",
+                        14: "server_hello_done",    15: "certificate_verify",
+                        16: "client_key_exchange",  20: "finished",
+                        21: "certificate_url",      22: "certificate_status",
+                        23: "supplemental_data" }
+
+
+class _TLSHandshake(_GenericTLSSessionInheritance):
+    """
+    Inherited by other Handshake classes to get post_build().
+    Also used as a fallback for unknown TLS Handshake packets.
+    """
+    name = "TLS Handshake Generic message"
+    fields_desc = [ ByteEnumField("msgtype", None, _tls_handshake_type),
+                    ThreeBytesField("msglen", None),
+                    StrLenField("msg", "",
+                                length_from=lambda pkt: pkt.msglen) ]
+
+    def post_build(self, p, pay):
+        l = len(p)
+        if self.msglen is None:
+            l2 = l - 4
+            p = struct.pack("!I", (ord(p[0]) << 24) | l2) + p[4:]
+        return p + pay
+
+    def guess_payload_class(self, p):
+        return Padding
+
+    def tls_session_update(self, msg_str):
+        """
+        Covers both post_build- and post_dissection- context updates.
+        """
+        self.tls_session.handshake_messages.append(msg_str)
+        self.tls_session.handshake_messages_parsed.append(self)
+
+
+###############################################################################
+### HelloRequest                                                            ###
+###############################################################################
+
+class TLSHelloRequest(_TLSHandshake):
+    name = "TLS Handshake - Hello Request"
+    fields_desc = [ ByteEnumField("msgtype", 0, _tls_handshake_type),
+                    ThreeBytesField("msglen", None) ]
+
+    def tls_session_update(self, msg_str):
+        """
+        Message should not be added to the list of handshake messages
+        that will be hashed in the finished and certificate verify messages.
+        """
+        return
+
+
+###############################################################################
+### ClientHello fields                                                      ###
+###############################################################################
+
+class _GMTUnixTimeField(IntField):
+    """
+    Piggybacked from scapy6 UTCTimeField
+    "The current time and date in standard UNIX 32-bit format (seconds since
+     the midnight starting Jan 1, 1970, GMT, ignoring leap seconds)."
+    """
+    epoch = (1970, 1, 1, 0, 0, 0, 3, 1, 0)
+
+    def i2repr(self, pkt, x):
+        x = self.i2h(pkt, x)
+        from time import gmtime, strftime, mktime
+        delta = mktime(gmtime(0)) - mktime(self.epoch)
+        x = x-delta
+        t = strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime(x))
+        return "%s (%d)" % (t, x)
+
+    def i2h(self, pkt, x):
+        if x is not None:
+            return x
+        return 0
+
+class _TLSRandomBytesField(StrFixedLenField):
+    def i2repr(self, pkt, x):
+        if x is None:
+            return repr(x)
+        return repr_hex(self.i2h(pkt,x))
+
+
+class _SessionIDField(StrLenField):
+    """
+    opaque SessionID<0..32>; section 7.4.1.2 of RFC 4346
+    """
+    pass
+
+
+class _CipherSuitesField(StrLenField):
+    __slots__ = ["itemfmt", "itemsize", "i2s", "s2i"]
+    islist = 1
+    def __init__(self, name, default, dico, length_from=None, itemfmt="!H"):
+        StrLenField.__init__(self, name, default, length_from=length_from)
+        self.itemfmt = itemfmt
+        self.itemsize = struct.calcsize(itemfmt)
+        i2s = self.i2s = {}
+        s2i = self.s2i = {}
+        keys = dico.keys()
+        for k in keys:
+            i2s[k] = dico[k]
+            s2i[dico[k]] = k
+
+    def any2i_one(self, pkt, x):
+        if (isinstance(x, _GenericCipherSuite) or
+            isinstance(x, _GenericCipherSuiteMetaclass)):
+            x = x.val
+        if type(x) is str:
+            x = self.s2i[x]
+        return x
+
+    def i2repr_one(self, pkt, x):
+        fmt = "0x%%0%dx" % self.itemsize
+        return self.i2s.get(x, fmt % x)
+
+    def any2i(self, pkt, x):
+        if type(x) is not list:
+            x = [x]
+        return map(lambda z,pkt=pkt:self.any2i_one(pkt,z), x)
+
+    def i2repr(self, pkt, x):
+        if x is None:
+            return "None"
+        l = map(lambda z,pkt=pkt:self.i2repr_one(pkt,z), x)
+        if len(l) == 1:
+            l = l[0]
+        else:
+            l = "[%s]" % ", ".join(l)
+        return l
+
+    def i2m(self, pkt, val):
+        if val is None:
+            val = []
+        return "".join(map(lambda x: struct.pack(self.itemfmt, x), val))
+
+    def m2i(self, pkt, m):
+        res = []
+        itemlen = struct.calcsize(self.itemfmt)
+        while m:
+            res.append(struct.unpack(self.itemfmt, m[:itemlen])[0])
+            m = m[itemlen:]
+        return res
+
+    def i2len(self, pkt, i):
+        return len(i)*self.itemsize
+
+
+class _CompressionMethodsField(_CipherSuitesField):
+
+    def any2i_one(self, pkt, x):
+        if (isinstance(x, _GenericComp) or
+            isinstance(x, _GenericCompMetaclass)):
+            x = x.val
+        if type(x) is str:
+            x = self.s2i[x]
+        return x
+
+
+###############################################################################
+### ClientHello/ServerHello extensions                                      ###
+###############################################################################
+
+# We provide these extensions mostly for packet manipulation purposes.
+# For now, most of them are not considered by our automaton.
+
+_tls_ext = {  0: "server_name",             # RFC 4366
+              1: "max_fragment_length",     # RFC 4366
+              2: "client_certificate_url",  # RFC 4366
+              3: "trusted_ca_keys",         # RFC 4366
+              4: "truncated_hmac",          # RFC 4366
+              5: "status_request",          # RFC 4366
+              6: "user_mapping",            # RFC 4681
+              7: "client_authz",            # RFC 5878
+              8: "server_authz",            # RFC 5878
+              9: "cert_type",               # RFC 6091
+             10: "elliptic_curves",         # RFC 4492
+             11: "ec_point_formats",        # RFC 4492
+             13: "signature_algorithms",    # RFC 5246
+             0x0f: "heartbeat",             # RFC 6520
+             0x10: "alpn",                  # RFC 7301
+             0x15: "padding",               # RFC 7685
+             0x23: "session_ticket",        # RFC 5077
+             0x3374: "next_protocol_negotiation",
+                                            # RFC-draft-agl-tls-nextprotoneg-03
+             0xff01: "renegotiation_info"   # RFC 5746
+             }
+
+
+class TLS_Ext_Unknown(_GenericTLSSessionInheritance):
+    name = "TLS Extension - Scapy Unknown"
+    fields_desc = [ShortEnumField("type", None, _tls_ext),
+                   FieldLenField("len", None, fmt="!H", length_of="val"),
+                   StrLenField("val", "",
+                               length_from=lambda pkt: pkt.len) ]
+
+    def post_build(self, p, pay):
+        if self.len is None:
+            l = len(p) - 4
+            p = p[:2] + struct.pack("!H", l) + p[4:]
+        return p+pay
+
+class TLS_Ext_PrettyPacketList(TLS_Ext_Unknown):
+    """
+    Dummy extension used for server_name/ALPN/NPN for a lighter representation:
+    the final field is showed as a 1-line list rather than as lots of packets.
+    XXX Define a new condition for packet lists in Packet._show_or_dump?
+    """
+    def _show_or_dump(self, dump=False, indent=3,
+                      lvl="", label_lvl="", first_call=True):
+        """ Reproduced from packet.py """
+        ct = AnsiColorTheme() if dump else conf.color_theme
+        s = "%s%s %s %s \n" % (label_lvl, ct.punct("###["),
+                               ct.layer_name(self.name), ct.punct("]###"))
+        for f in self.fields_desc[:-1]:
+            ncol = ct.field_name
+            vcol = ct.field_value
+            fvalue = self.getfieldval(f.name)
+            begn = "%s  %-10s%s " % (label_lvl+lvl, ncol(f.name),
+                                     ct.punct("="),)
+            reprval = f.i2repr(self,fvalue)
+            if type(reprval) is str:
+                reprval = reprval.replace("\n", "\n"+" "*(len(label_lvl)
+                                                          +len(lvl)
+                                                          +len(f.name)
+                                                          +4))
+            s += "%s%s\n" % (begn,vcol(reprval))
+        f = self.fields_desc[-1]
+        ncol = ct.field_name
+        vcol = ct.field_value
+        fvalue = self.getfieldval(f.name)
+        begn = "%s  %-10s%s " % (label_lvl+lvl, ncol(f.name), ct.punct("="),)
+        reprval = f.i2repr(self,fvalue)
+        if type(reprval) is str:
+            reprval = reprval.replace("\n", "\n"+" "*(len(label_lvl)
+                                                      +len(lvl)
+                                                      +len(f.name)
+                                                      +4))
+        s += "%s%s\n" % (begn,vcol(reprval))
+        if self.payload:
+            s += self.payload._show_or_dump(dump=dump, indent=indent,
+                                lvl=lvl+(" "*indent*self.show_indent),
+                                label_lvl=label_lvl, first_call=False)
+
+        if first_call and not dump:
+            print s
+        else:
+            return s
+
+
+_tls_server_name_types = { 0: "host_name" }
+
+class ServerName(Packet):
+    name = "HostName"
+    fields_desc = [ ByteEnumField("nametype", 0, _tls_server_name_types),
+                    FieldLenField("namelen", None, length_of="servername"),
+                    StrLenField("servername", "",
+                                length_from=lambda pkt: pkt.namelen) ]
+    def guess_payload_class(self, p):
+        return Padding
+
+class ServerListField(PacketListField):
+    def i2repr(self, pkt, x):
+        res = [p.servername for p in x]
+        return "[%s]" % ", ".join(res)
+
+class TLS_Ext_ServerName(TLS_Ext_PrettyPacketList):                 # RFC 4366
+    name = "TLS Extension - Server Name"
+    fields_desc = [ShortEnumField("type", 0, _tls_ext),
+                   FieldLenField("len", None, length_of="servernames",
+                                 adjust=lambda pkt,x: x+2),
+                   FieldLenField("servernameslen", None,
+                                 length_of="servernames"),
+                   ServerListField("servernames", [], ServerName,
+                                   length_from=lambda pkt: pkt.servernameslen)]
+
+
+class TLS_Ext_MaxFragLen(TLS_Ext_Unknown):                          # RFC 4366
+    name = "TLS Extension - Server Name"
+    fields_desc = [ShortEnumField("type", 1, _tls_ext),
+                   ShortField("len", None),
+                   ByteEnumField("maxfraglen", 4, { 1: "2^9",
+                                                    2: "2^10",
+                                                    3: "2^11",
+                                                    4: "2^12" }) ]
+
+
+class TLS_Ext_ClientCertURL(TLS_Ext_Unknown):                       # RFC 4366
+    name = "TLS Extension - Server Name"
+    fields_desc = [ShortEnumField("type", 2, _tls_ext),
+                   ShortField("len", None) ]
+
+
+_tls_trusted_authority_types = {0: "pre_agreed",
+                                1: "key_sha1_hash",
+                                2: "x509_name",
+                                3: "cert_sha1_hash" }
+
+class TAPreAgreed(Packet):
+    name = "Trusted authority - pre_agreed"
+    fields_desc = [ ByteEnumField("idtype", 0, _tls_trusted_authority_types) ]
+    def guess_payload_class(self, p):
+        return Padding
+
+class TAKeySHA1Hash(Packet):
+    name = "Trusted authority - key_sha1_hash"
+    fields_desc = [ ByteEnumField("idtype", 1, _tls_trusted_authority_types),
+                    StrFixedLenField("id", None, 20) ]
+    def guess_payload_class(self, p):
+        return Padding
+
+class TAX509Name(Packet):
+    """
+    XXX Section 3.4 of RFC 4366. Implement a more specific DNField
+    rather than current StrLenField.
+    """
+    name = "Trusted authority - x509_name"
+    fields_desc = [ ByteEnumField("idtype", 2, _tls_trusted_authority_types),
+                    FieldLenField("dnlen", None, length_of="dn"),
+                    StrLenField("dn", "", length_from=lambda pkt: pkt.dnlen) ]
+    def guess_payload_class(self, p):
+        return Padding
+
+class TACertSHA1Hash(Packet):
+    name = "Trusted authority - cert_sha1_hash"
+    fields_desc = [ ByteEnumField("idtype", 3, _tls_trusted_authority_types),
+                    StrFixedLenField("id", None, 20) ]
+    def guess_payload_class(self, p):
+        return Padding
+
+_tls_trusted_authority_cls = {0: TAPreAgreed,
+                              1: TAKeySHA1Hash,
+                              2: TAX509Name,
+                              3: TACertSHA1Hash }
+
+class _TAListField(PacketListField):
+    """
+    Specific version that selects the right Trusted Authority (previous TA*)
+    class to be used for dissection based on idtype.
+    """
+    def m2i(self, pkt, m):
+        idtype = ord(m[0])
+        cls = self.cls
+        if _tls_trusted_authority_cls.has_key(idtype):
+            cls = _tls_trusted_authority_cls[idtype]
+        return cls(m)
+
+class TLS_Ext_TrustedCAInd(TLS_Ext_Unknown):                        # RFC 4366
+    name = "TLS Extension - Trusted CA Indication"
+    fields_desc = [ShortEnumField("type", 3, _tls_ext),
+                   ShortField("len", None),
+                   FieldLenField("talen", None, length_of="ta"),
+                   _TAListField("ta", [], Raw,
+                                length_from=lambda pkt: pkt.talen) ]
+
+
+class TLS_Ext_TruncatedHMAC(TLS_Ext_Unknown):                       # RFC 4366
+    name = "TLS Extension - Truncated HMAC"
+    fields_desc = [ShortEnumField("type", 4, _tls_ext),
+                   ShortField("len", None) ]
+
+
+class ResponderID(Packet):
+    name = "Responder ID structure"
+    fields_desc = [ FieldLenField("respidlen", None, length_of="respid"),
+                    StrLenField("respid", "",
+                                length_from=lambda pkt: pkt.respidlen)]
+    def guess_payload_class(self, p):
+        return Padding
+
+class OCSPStatusRequest(Packet):
+    """
+    This is the structure defined in RFC 6066, not in RFC 6960!
+    """
+    name = "OCSPStatusRequest structure"
+    fields_desc = [ FieldLenField("respidlen", None, length_of="respid"),
+                    PacketListField("respid", [], ResponderID,
+                                    length_from=lambda pkt: pkt.respidlen),
+                    FieldLenField("reqextlen", None, length_of="reqext"),
+                    PacketField("reqext", "", X509_Extensions) ]
+    def guess_payload_class(self, p):
+        return Padding
+
+_cert_status_type = { 1: "ocsp" }
+_cert_status_req_cls  = { 1: OCSPStatusRequest }
+
+class _StatusReqField(PacketListField):
+    def m2i(self, pkt, m):
+        idtype = pkt.stype
+        cls = self.cls
+        if _cert_status_req_cls.has_key(idtype):
+            cls = _cert_status_req_cls[idtype]
+        return cls(m)
+
+class TLS_Ext_CSR(TLS_Ext_Unknown):                                 # RFC 4366
+    name = "TLS Extension - Certificate Status Request"
+    fields_desc = [ShortEnumField("type", 5, _tls_ext),
+                   ShortField("len", None),
+                   ByteEnumField("stype", None, _cert_status_type),
+                   _StatusReqField("req", [], Raw,
+                                  length_from=lambda pkt: pkt.len - 1) ]
+
+
+class TLS_Ext_UserMapping(TLS_Ext_Unknown):                         # RFC 4681
+    name = "TLS Extension - User Mapping"
+    fields_desc = [ShortEnumField("type", 6, _tls_ext),
+                   ShortField("len", None),
+                   FieldLenField("umlen", None, fmt="B", length_of="um"),
+                   FieldListField("um", [],
+                                  ByteField("umtype", 0),
+                                  length_from=lambda pkt: pkt.umlen) ]
+
+
+class TLS_Ext_ClientAuthz(TLS_Ext_Unknown):                         # RFC 5878
+    """ XXX Unsupported """
+    name = "TLS Extension - Client Authz"
+    fields_desc = [ShortEnumField("type", 7, _tls_ext),
+                   ShortField("len", None),
+                   ]
+
+class TLS_Ext_ServerAuthz(TLS_Ext_Unknown):                         # RFC 5878
+    """ XXX Unsupported """
+    name = "TLS Extension - Server Authz"
+    fields_desc = [ShortEnumField("type", 8, _tls_ext),
+                   ShortField("len", None),
+                   ]
+
+
+_tls_cert_types = { 0: "X.509", 1: "OpenPGP" }
+
+class TLS_Ext_ClientCertType(TLS_Ext_Unknown):                      # RFC 5081
+    name = "TLS Extension - Certificate Type (client version)"
+    fields_desc = [ShortEnumField("type", 9, _tls_ext),
+                   ShortField("len", None),
+                   FieldLenField("ctypeslen", None, length_of="ctypes"),
+                   FieldListField("ctypes", [0, 1],
+                                  ByteEnumField("certtypes", None,
+                                                _tls_cert_types),
+                                  length_from=lambda pkt: pkt.ctypeslen) ]
+
+class TLS_Ext_ServerCertType(TLS_Ext_Unknown):                      # RFC 5081
+    name = "TLS Extension - Certificate Type (server version)"
+    fields_desc = [ShortEnumField("type", 9, _tls_ext),
+                   ShortField("len", None),
+                   ByteEnumField("ctype", None, _tls_cert_types) ]
+
+def _TLS_Ext_CertTypeDispatcher(m, *args, **kargs):
+    """
+    We need to select the correct one on dissection. We use the length for
+    that, as 1 for client version would emply an empty list.
+    """
+    l = struct.unpack("!H", m[2:4])[0]
+    if l == 1:
+        cls = TLS_Ext_ServerCertType
+    else:
+        cls = TLS_Ext_ClientCertType
+    return cls(m, *args, **kargs)
+
+
+class TLS_Ext_SupportedEllipticCurves(TLS_Ext_Unknown):             # RFC 4492
+    name = "TLS Extension - Supported Elliptic Curves"
+    fields_desc = [ShortEnumField("type", 10, _tls_ext),
+                   ShortField("len", None),
+                   FieldLenField("ecllen", None, length_of="ecl"),
+                   FieldListField("ecl", [],
+                                    ShortEnumField("nc", None,
+                                                   _tls_named_curves),
+                                    length_from=lambda pkt: pkt.ecllen) ]
+
+
+_tls_ecpoint_format = { 0: "uncompressed",
+                        1: "ansiX962_compressed_prime",
+                        2: "ansiX962_compressed_char2" }
+
+class TLS_Ext_SupportedPointFormat(TLS_Ext_Unknown):                # RFC 4492
+    name = "TLS Extension - Supported Point Format"
+    fields_desc = [ShortEnumField("type", 11, _tls_ext),
+                   ShortField("len", None),
+                   FieldLenField("ecpllen", None, fmt="B", length_of="ecpl"),
+                   FieldListField("ecpl", [0],
+                                    ByteEnumField("nc", None,
+                                                  _tls_ecpoint_format),
+                                    length_from=lambda pkt: pkt.ecpllen) ]
+
+
+class TLS_Ext_SignatureAlgorithms(TLS_Ext_Unknown):                 # RFC 5246
+    name = "TLS Extension - Signature Algorithms"
+    fields_desc = [ShortEnumField("type", 13, _tls_ext),
+                   ShortField("len", None),
+                   SigAndHashAlgsLenField("sig_algs_len", None,
+                                          length_of="sig_algs"),
+                   SigAndHashAlgsField("sig_algs", [],
+                                       EnumField("hash_sig", None,
+                                                    _tls_hash_sig),
+                                       length_from=
+                                           lambda pkt: pkt.sig_algs_len) ]
+
+
+class TLS_Ext_Heartbeat(TLS_Ext_Unknown):                           # RFC 6520
+    name = "TLS Extension - Heartbeat"
+    fields_desc = [ShortEnumField("type", 0x0f, _tls_ext),
+                   ShortField("len", None),
+                   ByteEnumField("heartbeat_mode", 2,
+                       { 1: "peer_allowed_to_send",
+                         2: "peer_not_allowed_to_send" }) ]
+
+
+class ProtocolName(Packet):
+    name = "Protocol Name"
+    fields_desc = [ FieldLenField("len", None, fmt='B', length_of="protocol"),
+                    StrLenField("protocol", "",
+                                length_from=lambda pkt: pkt.len)]
+    def guess_payload_class(self, p):
+        return Padding
+
+class ProtocolListField(PacketListField):
+    def i2repr(self, pkt, x):
+        res = [p.protocol for p in x]
+        return "[%s]" % ", ".join(res)
+
+class TLS_Ext_ALPN(TLS_Ext_PrettyPacketList):                       # RFC 7301
+    name = "TLS Extension - Application Layer Protocol Negotiation"
+    fields_desc = [ShortEnumField("type", 0x10, _tls_ext),
+                   ShortField("len", None),
+                   FieldLenField("protocolslen", None, length_of="protocols"),
+                   ProtocolListField("protocols", [], ProtocolName,
+                                     length_from=lambda pkt:pkt.protocolslen) ]
+
+
+class TLS_Ext_Padding(TLS_Ext_Unknown):                             # RFC 7685
+    name = "TLS Extension - Padding"
+    fields_desc = [ShortEnumField("type", 0x15, _tls_ext),
+                   FieldLenField("len", None, length_of="padding"),
+                   StrLenField("padding", "",
+                               length_from=lambda pkt: pkt.len) ]
+
+
+class TLS_Ext_SessionTicket(TLS_Ext_Unknown):                       # RFC 5077
+    """
+    RFC 5077 updates RFC 4507 according to most implementations, which do not
+    use another (useless) 'ticketlen' field after the global 'len' field.
+    """
+    name = "TLS Extension - Session Ticket"
+    fields_desc = [ShortEnumField("type", 0x23, _tls_ext),
+                   FieldLenField("len", None, length_of="ticket"),
+                   StrLenField("ticket", "",
+                               length_from=lambda pkt: pkt.len) ]
+
+
+class TLS_Ext_NPN(TLS_Ext_PrettyPacketList):
+    """
+    Defined in RFC-draft-agl-tls-nextprotoneg-03. Deprecated in favour of ALPN.
+    """
+    name = "TLS Extension - Next Protocol Negotiation"
+    fields_desc = [ShortEnumField("type", 0x3374, _tls_ext),
+                   FieldLenField("len", None, length_of="protocols"),
+                   ProtocolListField("protocols", [], ProtocolName,
+                                     length_from=lambda pkt:pkt.len) ]
+
+
+class TLS_Ext_RenegotiationInfo(TLS_Ext_Unknown):                   # RFC 5746
+    name = "TLS Extension - Renegotiation Indication"
+    fields_desc = [ShortEnumField("type", 0xff01, _tls_ext),
+                   ShortField("len", None),
+                   FieldLenField("reneg_conn_len", None, fmt='B',
+                                 length_of="renegotiated_connection"),
+                   StrLenField("renegotiated_connection", "",
+                               length_from=lambda pkt: pkt.reneg_conn_len) ]
+
+
+_tls_ext_cls = { 0: TLS_Ext_ServerName,
+                 1: TLS_Ext_MaxFragLen,
+                 2: TLS_Ext_ClientCertURL,
+                 3: TLS_Ext_TrustedCAInd,
+                 4: TLS_Ext_TruncatedHMAC,
+                 5: TLS_Ext_CSR,
+                 6: TLS_Ext_UserMapping,
+                 7: TLS_Ext_ClientAuthz,
+                 8: TLS_Ext_ServerAuthz,
+                 9: _TLS_Ext_CertTypeDispatcher,
+                10: TLS_Ext_SupportedEllipticCurves,
+                11: TLS_Ext_SupportedPointFormat,
+                13: TLS_Ext_SignatureAlgorithms,
+                0x0f: TLS_Ext_Heartbeat,
+                0x10: TLS_Ext_ALPN,
+                0x15: TLS_Ext_Padding,
+                0x23: TLS_Ext_SessionTicket,
+                0x3374: TLS_Ext_NPN,
+                0xff01: TLS_Ext_RenegotiationInfo
+                }
+
+
+class _ExtensionsLenField(FieldLenField):
+    """
+    This field provides the first half of extensions support implementation
+    as defined in RFC 3546. The second is provided by _ExtensionsField. Both
+    are used as the last fields at the end of ClientHello messages.
+
+    The idea is quite simple:
+    - dissection : the _ExtensionsLenField will compute the remaining length of
+    the message based on the value of a provided field (for instance 'msglen'
+    in ClientHello) and a list of other fields that are considered "shifters".
+    This shifters are length fields of some vectors. The sum of their value
+    will be substracted to the one of the main field. If the result is
+    positive, this means that extensions are present and the
+    _ExtensionsLenField behaves just like a normal FieldLenField. If the value
+    is null, invalid or not sufficient to grab a length, the getfield method of
+    the field will simply return a 0 value without "eating" bytes from current
+    string. In a sense, the field is always present (which means that its value
+    is available for the _ExtensionsField field) but the behavior during
+    dissection is conditional. Then, the _ExtensionsField uses the length value
+    from the _ExtensionsLenField, to know how much data it should grab (TLS
+    extension is basically a vector). If no extensions are present, the length
+    field will have a null value and nothing will be grabbed.
+
+    - build: during build, if some extensions are provided, the
+    _ExtensionsLenField will automatically access the whole length and use it
+    if the user does not provide a specific value. Now, if no extensions are
+    available and the user does not provide a specific value, nothing is added
+    during the build, i.e. no length field with a null value will appear. As a
+    side note, this is also the case for the rebuild of a dissected packet: if
+    the initial packet had a length field with a null value, one will be built.
+    If no length field was was present, nothing is added, i.e. a rebuilt
+    dissected packet will look like the original. Another side note is that the
+    shifters allow us to decide if there is an extension vector but the length
+    of that vector is grabbed from the value of the 2 first bytes, not from the
+    value computed from shifters and msglen.
+    """
+    __slots__ = ["lfld", "shifters"]
+    def __init__(self, name, default,
+                 lfld, shifters=[],
+                 fmt="!H", length_of=None):
+        FieldLenField.__init__(self, name, default,
+                               fmt=fmt, length_of=length_of)
+        self.lfld = lfld
+        self.shifters = shifters
+
+    def getfield(self, pkt, s):
+        # compute the length of remaining data to see if there are ext
+        l = getattr(pkt, self.lfld)
+        for fname in self.shifters:
+            if type(fname) is int:
+                l -= fname
+            else:
+                l -= getattr(pkt, fname)
+
+        if l is None or l <= 0 or l < self.sz:
+            return s, None  # let's consider there's no extensions
+
+        return Field.getfield(self, pkt, s)
+
+    def addfield(self, pkt, s, i):
+        if i is None:
+            if self.length_of is not None:
+                fld,fval = pkt.getfield_and_val(self.length_of)
+                f = fld.i2len(pkt, fval)
+                i = self.adjust(pkt, f)
+                if i == 0: # for correct build if no ext and not explicitly 0
+                    return s
+        return s + struct.pack(self.fmt, i)
+
+class _ExtensionsField(StrLenField):
+    """
+    See ExtensionsLenField documentation.
+    """
+    islist=1
+    holds_packets=1
+
+    def i2len(self, pkt, i):
+        if i is None:
+            return 0
+        return len(self.i2m(pkt, i))
+
+    def getfield(self, pkt, s):
+        l = self.length_from(pkt)
+        if l is None:
+            return s, []
+        return s[l:], self.m2i(pkt, s[:l])
+
+    def i2m(self, pkt, i):
+        if i is None:
+            return ""
+        return "".join(map(str, i))
+
+    def m2i(self, pkt, m):
+        res = []
+        while m:
+            t = struct.unpack("!H", m[:2])[0]
+            l = struct.unpack("!H", m[2:4])[0]
+            cls = _tls_ext_cls.get(t, TLS_Ext_Unknown)
+            res.append(cls(m[:l+4], tls_session=pkt.tls_session))
+            m = m[l+4:]
+        return res
+
+
+###############################################################################
+### ClientHello                                                             ###
+###############################################################################
+
+class TLSClientHello(_TLSHandshake):
+    """
+    TLS ClientHello, with abilities to handle extensions.
+
+    The Random structure follows the RFC 5246: while it is 32-byte long,
+    many implementations use the first 4 bytes as a gmt_unix_time, and then
+    the remaining 28 byts should be completely random. This was designed in
+    order to (sort of) mitigate broken RNGs. If you prefer to show the full
+    32 random bytes without any GMT time, just comment in/out the lines below.
+    """
+    name = "TLS Handshake - Client Hello"
+    fields_desc = [ ByteEnumField("msgtype", 1, _tls_handshake_type),
+                    ThreeBytesField("msglen", None),
+                    _TLSVersionField("version", 0x0303, _tls_version),
+
+                    #_TLSRandomBytesField("random_bytes", None, 32),
+                    _GMTUnixTimeField("gmt_unix_time", None),
+                    _TLSRandomBytesField("random_bytes", None, 28),
+
+                    FieldLenField("sidlen", None, fmt="B", length_of="sid"),
+                    _SessionIDField("sid", "",
+                                    length_from=lambda pkt:pkt.sidlen),
+
+                    FieldLenField("cipherslen", None, fmt="!H",
+                                  length_of="ciphers"),
+                    _CipherSuitesField("ciphers",
+                                       [TLS_DHE_RSA_WITH_AES_128_CBC_SHA],
+                                       _tls_cipher_suites, itemfmt="!H",
+                                       length_from=lambda pkt: pkt.cipherslen),
+
+                    FieldLenField("complen", None, fmt="B", length_of="comp"),
+                    _CompressionMethodsField("comp", [0],
+                                             _tls_compression_algs,
+                                             itemfmt="B",
+                                             length_from=
+                                                 lambda pkt: pkt.complen),
+
+                    _ExtensionsLenField("extlen", None, "msglen",
+                                       shifters = ["sidlen", "cipherslen",
+                                                   "complen", 38],
+                                       length_of="ext"),
+                    _ExtensionsField("ext", None,
+                                     length_from=lambda pkt: pkt.extlen) ]
+
+    def post_build(self, p, pay):
+        if self.random_bytes is None:
+            p = p[:10] + randstring(28) + p[10+28:]
+        return super(TLSClientHello, self).post_build(p, pay)
+
+    def tls_session_update(self, msg_str):
+        """
+        Either for parsing or building, we store the client_random
+        along with the raw string representing this handshake message.
+        """
+        self.tls_session.advertised_tls_version = self.version
+        self.random_bytes = msg_str[10:38]
+        self.tls_session.client_random = (struct.pack('!I',
+                                                      self.gmt_unix_time) +
+                                          self.random_bytes)
+        self.tls_session.handshake_messages.append(msg_str)
+        self.tls_session.handshake_messages_parsed.append(self)
+
+
+###############################################################################
+### ServerHello                                                             ###
+###############################################################################
+
+class TLSServerHello(TLSClientHello):
+    """
+    TLS ServerHello, with abilities to handle extensions.
+
+    The Random structure follows the RFC 5246: while it is 32-byte long,
+    many implementations use the first 4 bytes as a gmt_unix_time, and then
+    the remaining 28 byts should be completely random. This was designed in
+    order to (sort of) mitigate broken RNGs. If you prefer to show the full
+    32 random bytes without any GMT time, just comment in/out the lines below.
+    """
+    name = "TLS Handshake - Server Hello"
+    fields_desc = [ ByteEnumField("msgtype", 2, _tls_handshake_type),
+                    ThreeBytesField("msglen", None),
+                    _TLSVersionField("version", None, _tls_version),
+
+                    #_TLSRandomBytesField("random_bytes", None, 32),
+                    _GMTUnixTimeField("gmt_unix_time", None),
+                    _TLSRandomBytesField("random_bytes", None, 28),
+
+                    FieldLenField("sidlen", None, length_of="sid", fmt="B"),
+                    _SessionIDField("sid", "",
+                                   length_from = lambda pkt: pkt.sidlen),
+
+                    EnumField("cipher", None, _tls_cipher_suites),
+                    _CompressionMethodsField("comp", [0],
+                                             _tls_compression_algs,
+                                             itemfmt="B",
+                                             length_from=lambda pkt: 1),
+
+                    _ExtensionsLenField("extlen", None, "msglen",
+                                        shifters = ["sidlen", 38],
+                                        length_of="ext"),
+                    _ExtensionsField("ext", [],
+                                     length_from=lambda pkt: pkt.extlen) ]
+
+    def tls_session_update(self, msg_str):
+        """
+        Either for parsing or building, we store the server_random
+        along with the raw string representing this handshake message.
+        We also store the session_id, the cipher suite (if recognized),
+        the compression method, and finally we instantiate the pending write
+        and read connection states. Usually they get updated later on in the
+        negotiation when we learn the session keys, and eventually they
+        are committed once a ChangeCipherSpec has been sent/received.
+        """
+        self.tls_session.tls_version = self.version
+        self.random_bytes = msg_str[10:38]
+        self.tls_session.server_random = (struct.pack('!I',
+                                                      self.gmt_unix_time) +
+                                          self.random_bytes)
+        self.tls_session.handshake_messages.append(msg_str)
+        self.tls_session.handshake_messages_parsed.append(self)
+
+        self.tls_session.sid = self.sid
+
+        if self.cipher:
+            cs_val = self.cipher
+            if not _tls_cipher_suites_cls.has_key(cs_val):
+                warning("Unknown cipher suite %d from ServerHello" % cs_val)
+                # we do not try to set a default nor stop the execution
+            else:
+                cs_cls = _tls_cipher_suites_cls[cs_val]
+
+        if self.comp:
+            comp_val = self.comp[0]
+            if not _tls_compression_algs_cls.has_key(comp_val):
+                err = "Unknown compression alg %d from ServerHello" % comp_val
+                warning(err)
+                comp_val = 0
+            comp_cls = _tls_compression_algs_cls[comp_val]
+
+        connection_end = self.tls_session.connection_end
+        self.tls_session.pwcs = writeConnState(ciphersuite=cs_cls,
+                                               compression_alg=comp_cls,
+                                               connection_end=connection_end,
+                                               tls_version=self.version)
+        self.tls_session.prcs = readConnState(ciphersuite=cs_cls,
+                                              compression_alg=comp_cls,
+                                              connection_end=connection_end,
+                                              tls_version=self.version)
+
+
+###############################################################################
+### Certificate                                                             ###
+###############################################################################
+
+class _ASN1CertLenField(FieldLenField):
+    """
+    This is mostly a 3-byte FieldLenField.
+    """
+    def __init__(self, name, default, length_of=None, adjust=lambda pkt, x: x):
+        self.length_of = length_of
+        self.adjust = adjust
+        Field.__init__(self, name, default, fmt="!I")
+
+    def i2m(self, pkt, x):
+        if x is None:
+            if self.length_of is not None:
+                fld,fval = pkt.getfield_and_val(self.length_of)
+                f = fld.i2len(pkt, fval)
+                x = self.adjust(pkt, f)
+        return x
+
+    def addfield(self, pkt, s, val):
+        return s + struct.pack(self.fmt, self.i2m(pkt,val))[1:4]
+
+    def getfield(self, pkt, s):
+        return s[3:], self.m2i(pkt, struct.unpack(self.fmt, "\x00" + s[:3])[0])
+
+
+class _ASN1CertListField(StrLenField):
+    islist = 1
+    def i2len(self, pkt, i):
+        if i is None:
+            return 0
+        return len(self.i2m(pkt, i))
+
+    def getfield(self, pkt, s):
+        """
+        Extract Certs in a loop.
+        XXX We should providesafeguards when trying to parse a Cert.
+        """
+        l = None
+        if self.length_from is not None:
+            l = self.length_from(pkt)
+
+        lst = []
+        ret = ""
+        m = s
+        if l is not None:
+            m, ret = s[:l], s[l:]
+        while m:
+            clen = struct.unpack("!I", '\x00' + m[:3])[0]
+            lst.append((clen, Cert(m[3:3 + clen])))
+            m = m[3 + clen:]
+        return m + ret, lst
+
+    def i2m(self, pkt, i):
+        def i2m_one(i):
+            if type(i) is str:
+                return i
+            if isinstance(i, Cert):
+                s = i.der
+                l = struct.pack("!I", len(s))[1:4]
+                return l + s
+
+            (l, s) = i
+            if isinstance(s, Cert):
+                s = s.der
+            return struct.pack("!I", l)[1:4] + s
+
+        if i is None:
+            return ""
+        if type(i) is str:
+            return i
+        if isinstance(i, Cert):
+            i = [i]
+        return "".join(map(lambda x: i2m_one(x), i))
+
+    def any2i(self, pkt, x):
+        return x
+
+
+class TLSCertificate(_TLSHandshake):
+    """
+    XXX We do not support RFC 5081, i.e. OpenPGP certificates.
+    """
+    name = "TLS Handshake - Certificate"
+    fields_desc = [ ByteEnumField("msgtype", 11, _tls_handshake_type),
+                    ThreeBytesField("msglen", None),
+                    _ASN1CertLenField("certslen", None, length_of="certs"),
+                    _ASN1CertListField("certs", [],
+                                      length_from = lambda pkt: pkt.certslen) ]
+
+    def post_dissection_tls_session_update(self, msg_str):
+        connection_end = self.tls_session.connection_end
+        if connection_end == "client":
+            self.tls_session.server_certs = map(lambda x: x[1], self.certs)
+        else:
+            self.tls_session.client_certs = map(lambda x: x[1], self.certs)
+        self.tls_session.handshake_messages.append(msg_str)
+        self.tls_session.handshake_messages_parsed.append(self)
+
+
+###############################################################################
+### ServerKeyExchange                                                       ###
+###############################################################################
+
+class TLSServerKeyExchange(_TLSHandshake):
+    name = "TLS Handshake - Server Key Exchange"
+    fields_desc = [ ByteEnumField("msgtype", 12, _tls_handshake_type),
+                    ThreeBytesField("msglen", None),
+                    _TLSServerParamsField("params", None,
+                        length_from=lambda pkt: pkt.msglen),
+                    _TLSSignatureField("sig", None,
+                        length_from=lambda pkt: pkt.msglen - len(pkt.params)) ]
+
+    def build(self, *args, **kargs):
+        """
+        We overload build() method in order to provide a valid default value
+        for params based on TLS session if not provided. This cannot be done by
+        overriding i2m() because the method is called on a copy of the packet.
+
+        The 'params' field is built according to key_exchange.server_kx_msg_cls
+        which should have been set after receiving a cipher suite in a
+        previous ServerHello. Usual cases are:
+        - None: for RSA encryption or fixed FF/ECDH. This should never happen,
+          as no ServerKeyExchange should be generated in the first place.
+        - ServerDHParams: for ephemeral FFDH. In that case, the parameter to
+          server_kx_msg_cls does not matter.
+        - ServerECDH*Params: for ephemeral ECDH. There are actually three
+          classes, which are dispatched by _tls_server_ecdh_cls_guess on
+          the first byte retrieved. The default here is "\03", which
+          corresponds to ServerECDHNamedCurveParams (implicit curves).
+
+        When the Server*DHParams are built via .fill_missing(), the session
+        server_kx_params and client_kx_params will be updated accordingly.
+        """
+        fval = self.getfieldval("params")
+        if fval is None:
+            s = self.tls_session
+            if s.pwcs:
+                if s.pwcs.key_exchange.export:
+                    cls = ServerRSAParams(tls_session=s)
+                else:
+                    cls = s.pwcs.key_exchange.server_kx_msg_cls("\x03")
+                    cls = cls(tls_session=s)
+                try:
+                    cls.fill_missing()
+                except:
+                    pass
+            else:
+                cls = Raw()
+            self.params = cls
+
+        fval = self.getfieldval("sig")
+        if fval is None:
+            s = self.tls_session
+            if s.pwcs:
+                if not s.pwcs.key_exchange.anonymous:
+                    p = self.params
+                    if p is None:
+                        p = ""
+                    m = s.client_random + s.server_random + str(p)
+                    cls = _TLSSignature(tls_session=s)
+                    cls._update_sig(m, s.server_key)
+                else:
+                    cls = Raw()
+            else:
+                cls = Raw()
+            self.sig = cls
+
+        return _TLSHandshake.build(self, *args, **kargs)
+
+    def post_dissection(self, pkt):
+        """
+        While previously dissecting Server*DHParams, the session
+        server_kx_params and client_kx_params should have been updated.
+
+        XXX Add a 'fixed_dh' OR condition to the 'anonymous' test.
+        """
+        s = self.tls_session
+        if s.prcs and s.prcs.key_exchange.anonymous:
+            print "USELESS SERVER KEY EXCHANGE"
+        if (s.client_random and s.server_random and
+            s.server_certs and len(s.server_certs) > 0):
+            m = s.client_random + s.server_random + str(self.params)
+            sig_test = self.sig._verify_sig(m, s.server_certs[0])
+            if not sig_test:
+                print "INVALID SERVER KEY EXCHANGE SIGNATURE"
+
+
+###############################################################################
+### CertificateRequest                                                      ###
+###############################################################################
+
+_tls_client_certificate_types =  {  1: "rsa_sign",
+                                    2: "dss_sign",
+                                    3: "rsa_fixed_dh",
+                                    4: "dss_fixed_dh",
+                                    5: "rsa_ephemeral_dh_RESERVED",
+                                    6: "dss_ephemeral_dh_RESERVED",
+                                   20: "fortezza_dms_RESERVED",
+                                   64: "ecdsa_sign",
+                                   65: "rsa_fixed_ecdh",
+                                   66: "ecdsa_fixed_ecdh" }
+
+
+class _CertTypesField(_CipherSuitesField):
+    pass
+
+class _CertAuthoritiesField(StrLenField):
+    """
+    XXX Rework this with proper ASN.1 parsing.
+    """
+    islist = 1
+
+    def getfield(self, pkt, s):
+        l = self.length_from(pkt)
+        return s[l:], self.m2i(pkt, s[:l])
+
+    def m2i(self, pkt, m):
+        res = []
+        while len(m) > 1:
+            l = struct.unpack("!H", m[:2])[0]
+            if len(m) < l + 2:
+                res.append((l, m[2:]))
+                break
+            dn = m[2:2+l]
+            res.append((l, dn))
+            m = m[2+l:]
+        return res
+
+    def i2m(self, pkt, i):
+        return "".join(map(lambda (x,y): struct.pack("!H", x) + y, i))
+
+    def addfield(self, pkt, s, val):
+        return s + self.i2m(pkt, val)
+
+    def i2len(self, pkt, val):
+        if val is None:
+            return 0
+        else:
+            return len(self.i2m(pkt, val))
+
+
+class TLSCertificateRequest(_TLSHandshake):
+    name = "TLS Handshake - Certificate Request"
+    fields_desc = [ ByteEnumField("msgtype", 13, _tls_handshake_type),
+                    ThreeBytesField("msglen", None),
+                    FieldLenField("ctypeslen", None, fmt="B",
+                                  length_of="ctypes"),
+                    _CertTypesField("ctypes", [],
+                                    _tls_client_certificate_types,
+                                    itemfmt="!B",
+                                    length_from=lambda pkt: pkt.ctypeslen),
+                    SigAndHashAlgsLenField("sig_algs_len", None,
+                                           length_of="sig_algs"),
+                    SigAndHashAlgsField("sig_algs", [],
+                                        EnumField("hash_sig", None,
+                                                     _tls_hash_sig),
+                                        length_from=
+                                            lambda pkt: pkt.sig_algs_len),
+                    FieldLenField("certauthlen", None, fmt="!H",
+                                  length_of="certauth"),
+                    _CertAuthoritiesField("certauth", [],
+                                          length_from=
+                                              lambda pkt: pkt.certauthlen) ]
+
+
+###############################################################################
+### ServerHelloDone                                                         ###
+###############################################################################
+
+class TLSServerHelloDone(_TLSHandshake):
+    name = "TLS Handshake - Server Hello Done"
+    fields_desc = [ ByteEnumField("msgtype", 14, _tls_handshake_type),
+                    ThreeBytesField("msglen", None) ]
+
+
+###############################################################################
+### CertificateVerify                                                       ###
+###############################################################################
+
+class TLSCertificateVerify(_TLSHandshake):
+    name = "TLS Handshake - Certificate Verify"
+    fields_desc = [ ByteEnumField("msgtype", 15, _tls_handshake_type),
+                    ThreeBytesField("msglen", None),
+                    _TLSSignatureField("sig", None,
+                                 length_from = lambda pkt: pkt.msglen) ]
+
+    def build(self, *args, **kargs):
+        sig = self.getfieldval("sig")
+        if sig is None:
+            s = self.tls_session
+            m = "".join(s.handshake_messages)
+            self.sig = _TLSSignature(tls_session=s)
+            self.sig._update_sig(m, s.client_key)
+        return _TLSHandshake.build(self, *args, **kargs)
+
+    def post_dissection(self, pkt):
+        s = self.tls_session
+        m = "".join(s.handshake_messages)
+        if s.client_certs and len(s.client_certs) > 0:
+            sig_test = self.sig._verify_sig(m, s.client_certs[0])
+            if not sig_test:
+                print "INVALID CERTIFICATE VERIFY SIGNATURE"
+
+
+###############################################################################
+### ClientKeyExchange                                                       ###
+###############################################################################
+
+class _TLSCKExchKeysField(PacketField):
+    __slots__ = ["length_from"]
+    holds_packet = 1
+    def __init__(self, name, length_from=None, remain=0):
+        self.length_from = length_from
+        PacketField.__init__(self, name, None, None, remain=remain)
+
+    def m2i(self, pkt, m):
+        """
+        The client_kx_msg may be either None, EncryptedPreMasterSecret
+        (for RSA encryption key exchange), ClientDiffieHellmanPublic,
+        or ClientECDiffieHellmanPublic. When either one of them gets
+        dissected, the session context is updated accordingly.
+        """
+        l = self.length_from(pkt)
+        tbd, rem = m[:l], m[l:]
+
+        s = pkt.tls_session
+        cls = None
+
+        if s.prcs and s.prcs.key_exchange:
+            cls = s.prcs.key_exchange.client_kx_msg_cls
+
+        if cls is None:
+            return Raw(tbd)/Padding(rem)
+
+        return cls(tbd, tls_session=s)/Padding(rem)
+
+
+class TLSClientKeyExchange(_TLSHandshake):
+    """
+    This class mostly works like TLSServerKeyExchange and its 'params' field.
+    """
+    name = "TLS Handshake - Client Key Exchange"
+    fields_desc = [ ByteEnumField("msgtype", 16, _tls_handshake_type),
+                    ThreeBytesField("msglen", None),
+                    _TLSCKExchKeysField("exchkeys",
+                                        length_from = lambda pkt: pkt.msglen) ]
+
+    def build(self, *args, **kargs):
+        fval = self.getfieldval("exchkeys")
+        if fval is None:
+            s = self.tls_session
+            if s.prcs:
+                cls = s.prcs.key_exchange.client_kx_msg_cls
+                cls = cls(tls_session=s)
+            else:
+                cls = Raw()
+            self.exchkeys = cls
+        return _TLSHandshake.build(self, *args, **kargs)
+
+
+###############################################################################
+### Finished                                                                ###
+###############################################################################
+
+class _VerifyDataField(StrLenField):
+    def getfield(self, pkt, s):
+        if pkt.tls_session.tls_version == 0x300:
+            sep = 36
+        else:
+            sep = 12
+        return s[sep:], s[:sep]
+
+class TLSFinished(_TLSHandshake):
+    name = "TLS Handshake - Finished"
+    fields_desc = [ ByteEnumField("msgtype", 20, _tls_handshake_type),
+                    ThreeBytesField("msglen", None),
+                    _VerifyDataField("vdata", None) ]
+
+    def build(self, *args, **kargs):
+        fval = self.getfieldval("vdata")
+        if fval is None:
+            s = self.tls_session
+            handshake_msg = "".join(s.handshake_messages)
+            ms = s.master_secret
+            con_end = s.connection_end
+            self.vdata = s.wcs.prf.compute_verify_data(con_end, "write",
+                                                       handshake_msg, ms)
+        return _TLSHandshake.build(self, *args, **kargs)
+
+    def post_dissection(self, pkt):
+        s = self.tls_session
+        handshake_msg = "".join(s.handshake_messages)
+        if s.master_secret is not None:
+            ms = s.master_secret
+            con_end = s.connection_end
+            verify_data = s.rcs.prf.compute_verify_data(con_end, "read",
+                                                        handshake_msg, ms)
+            if self.vdata != verify_data:
+                print "INVALID TLS FINISHED RECEIVED"
+
+
+## Additional handshake messages
+
+###############################################################################
+### HelloVerifyRequest                                                      ###
+###############################################################################
+
+class TLSHelloVerifyRequest(_TLSHandshake):
+    """
+    Defined for DTLS, see RFC 6347.
+    """
+    name = "TLS Handshake - Hello Verify Request"
+    fields_desc = [ ByteEnumField("msgtype", 21, _tls_handshake_type),
+                    ThreeBytesField("msglen", None),
+                    FieldLenField("cookielen", None,
+                                  fmt="B", length_of="cookie"),
+                    StrLenField("cookie", "",
+                                length_from=lambda pkt: pkt.cookielen) ]
+
+
+###############################################################################
+### CertificateURL                                                          ###
+###############################################################################
+
+_tls_cert_chain_types = { 0: "individual_certs",
+                          1: "pkipath" }
+
+class URLAndOptionalHash(Packet):
+    name = "URLAndOptionHash structure for TLSCertificateURL"
+    fields_desc = [ FieldLenField("urllen", None, length_of="url"),
+                    StrLenField("url", "",
+                                length_from=lambda pkt: pkt.urllen),
+                    FieldLenField("hash_present", None,
+                                  fmt="B", length_of="hash",
+                                  adjust=lambda pkt,x: int(math.ceil(x/20.))),
+                    StrLenField("hash", "",
+                                length_from=lambda pkt: 20*pkt.hash_present) ]
+    def guess_payload_class(self, p):
+        return Padding
+
+class TLSCertificateURL(_TLSHandshake):
+    """
+    Defined in RFC 4366. PkiPath structure of section 8 is not implemented yet.
+    """
+    name = "TLS Handshake - Certificate URL"
+    fields_desc = [ ByteEnumField("msgtype", 21, _tls_handshake_type),
+                    ThreeBytesField("msglen", None),
+                    ByteEnumField("certchaintype", None, _tls_cert_chain_types),
+                    FieldLenField("uahlen", None, length_of="uah"),
+                    PacketListField("uah", [], URLAndOptionalHash,
+                                    length_from=lambda pkt: pkt.uahlen) ]
+
+
+###############################################################################
+### CertificateStatus                                                       ###
+###############################################################################
+
+class ThreeBytesLenField(FieldLenField):
+    def __init__(self, name, default,  length_of=None, adjust=lambda pkt, x:x):
+        FieldLenField.__init__(self, name, default, length_of=length_of,
+                               fmt='!I', adjust=adjust)
+    def i2repr(self, pkt, x):
+        if x is None:
+            return 0
+        return repr(self.i2h(pkt,x))
+    def addfield(self, pkt, s, val):
+        return s+struct.pack(self.fmt, self.i2m(pkt,val))[1:4]
+    def getfield(self, pkt, s):
+        return  s[3:], self.m2i(pkt, struct.unpack(self.fmt, "\x00"+s[:3])[0])
+
+_cert_status_cls  = { 1: OCSP_Response }
+
+class _StatusField(PacketField):
+    def m2i(self, pkt, m):
+        idtype = pkt.status_type
+        cls = self.cls
+        if _cert_status_cls.has_key(idtype):
+            cls = _cert_status_cls[idtype]
+        return cls(m)
+
+class TLSCertificateStatus(_TLSHandshake):
+    name = "TLS Handshake - Certificate Status"
+    fields_desc = [ ByteEnumField("msgtype", 22, _tls_handshake_type),
+                    ThreeBytesField("msglen", None),
+                    ByteEnumField("status_type", 1, _cert_status_type),
+                    ThreeBytesLenField("responselen", None,
+                                       length_of="response"),
+                    _StatusField("response", None, Raw) ]
+
+
+###############################################################################
+### SupplementalData                                                        ###
+###############################################################################
+
+class SupDataEntry(Packet):
+    name = "Supplemental Data Entry - Generic"
+    fields_desc = [ ShortField("sdtype", None),
+                    FieldLenField("len", None, length_of="data"),
+                    StrLenField("data", "",
+                                length_from=lambda pkt:pkt.len) ]
+    def guess_payload_class(self, p):
+        return Padding
+
+class UserMappingData(Packet):
+    name = "User Mapping Data"
+    fields_desc = [ ByteField("version", None),
+                    FieldLenField("len", None, length_of="data"),
+                    StrLenField("data", "",
+                                length_from=lambda pkt: pkt.len)]
+    def guess_payload_class(self, p):
+        return Padding
+
+class SupDataEntryUM(Packet):
+    name = "Supplemental Data Entry - User Mapping"
+    fields_desc = [ ShortField("sdtype", None),
+                    FieldLenField("len", None, length_of="data",
+                                  adjust=lambda pkt, x: x+2),
+                    FieldLenField("dlen", None, length_of="data"),
+                    PacketListField("data", [], UserMappingData,
+                                    length_from=lambda pkt:pkt.dlen) ]
+    def guess_payload_class(self, p):
+        return Padding
+
+class TLSSupplementalData(_TLSHandshake):
+    name = "TLS Handshake - Supplemental Data"
+    fields_desc = [ ByteEnumField("msgtype", 23, _tls_handshake_type),
+                    ThreeBytesField("msglen", None),
+                    ThreeBytesLenField("sdatalen", None, length_of="sdata"),
+                    PacketListField("sdata", [], SupDataEntry,
+                                    length_from=lambda pkt: pkt.sdatalen) ]
+
+
+###############################################################################
+### NewSessionTicket                                                        ###
+###############################################################################
+
+class Ticket(Packet):
+    name = "Recommended Ticket Construction"
+    fields_desc = [ StrFixedLenField("key_name", None, 16),
+                    StrFixedLenField("iv", None, 16),
+                    FieldLenField("estatelen", None, length_of="estate"),
+                    StrLenField("estate", "",
+                                length_from=lambda pkt: pkt.estatelen),
+                    StrFixedLenField("mac", None, 32) ]
+
+class TLSNewSessionTicket(_TLSHandshake):
+    """
+    XXX When knowing the right secret, we should be able to read the ticket.
+    """
+    name = "TLS Handshake - New Session Ticket"
+    fields_desc = [ ByteEnumField("msgtype", 4, _tls_handshake_type),
+                    ThreeBytesField("msglen", None),
+                    IntField("lifetime", 0xffffffff),
+                    FieldLenField("ticketlen", None, length_of="ticket"),
+                    StrLenField("ticket", "",
+                                length_from=lambda pkt: pkt.msglen) ]
+
+
+###############################################################################
+### All handshake messages defined in this module                           ###
+###############################################################################
+
+_tls_handshake_cls = { 0: TLSHelloRequest,          1: TLSClientHello,
+                       2: TLSServerHello,           3: TLSHelloVerifyRequest,
+                       4: TLSNewSessionTicket,      11: TLSCertificate,
+                       12: TLSServerKeyExchange,    13: TLSCertificateRequest,
+                       14: TLSServerHelloDone,      15: TLSCertificateVerify,
+                       16: TLSClientKeyExchange,    20: TLSFinished,
+                       21: TLSCertificateURL,       22: TLSCertificateStatus,
+                       23: TLSSupplementalData }
+
diff --git a/scapy/layers/tls/keyexchange.py b/scapy/layers/tls/keyexchange.py
new file mode 100644
index 0000000000000000000000000000000000000000..cfff57b6408c1df21de7c1119196a5edd8dcebc0
--- /dev/null
+++ b/scapy/layers/tls/keyexchange.py
@@ -0,0 +1,861 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+TLS key exchange logic.
+"""
+
+import math
+
+from cryptography.hazmat.backends import default_backend
+from cryptography.hazmat.primitives import serialization
+from cryptography.hazmat.primitives.asymmetric import dh, ec, rsa
+
+from scapy.config import conf
+from scapy.error import warning
+from scapy.fields import *
+from scapy.packet import Packet, Raw, Padding
+from scapy.layers.tls.cert import PubKeyRSA, PrivKeyRSA
+from scapy.layers.tls.session import _GenericTLSSessionInheritance
+from scapy.layers.tls.basefields import _tls_version, _TLSClientVersionField
+from scapy.layers.tls.crypto.pkcs1 import pkcs_i2osp, pkcs_os2ip
+from scapy.layers.tls.crypto.ffdh import FFDH_GROUPS
+
+
+###############################################################################
+### Common Fields                                                           ###
+###############################################################################
+
+_tls_hash_sig = { 0x0000: "none+anon",    0x0001: "none+rsa",
+                  0x0002: "none+dsa",     0x0003: "none+ecdsa",
+                  0x0100: "md5+anon",     0x0101: "md5+rsa",
+                  0x0102: "md5+dsa",      0x0103: "md5+ecdsa",
+                  0x0200: "sha1+anon",    0x0201: "sha1+rsa",
+                  0x0202: "sha1+dsa",     0x0203: "sha1+ecdsa",
+                  0x0300: "sha224+anon",  0x0301: "sha224+rsa",
+                  0x0302: "sha224+dsa",   0x0303: "sha224+ecdsa",
+                  0x0400: "sha256+anon",  0x0401: "sha256+rsa",
+                  0x0402: "sha256+dsa",   0x0403: "sha256+ecdsa",
+                  0x0500: "sha384+anon",  0x0501: "sha384+rsa",
+                  0x0502: "sha384+dsa",   0x0503: "sha384+ecdsa",
+                  0x0600: "sha512+anon",  0x0601: "sha512+rsa",
+                  0x0602: "sha512+dsa",   0x0603: "sha512+ecdsa" }
+
+
+def phantom_mode(pkt):
+    """
+    We expect this. If tls_version is not set, this means we did not process
+    any complete ClientHello, so we're most probably reading/building a
+    signature_algorithms extension, hence we cannot be in phantom_mode.
+    However, if the tls_version has been set, we test for TLS 1.2.
+    XXX Make this more generic. Also, factorize the classes below (metaclass?).
+    """
+    if not pkt.tls_session:
+        return False
+    if not pkt.tls_session.tls_version:
+        return False
+    return pkt.tls_session.tls_version < 0x0303
+
+def phantom_decorate(f, get_or_add):
+    """
+    Decorator for version-dependent fields.
+    If get_or_add is True (means get), we return s, self.phantom_value.
+    If it is False (means add), we return s.
+    """
+    def wrapper(*args):
+        self, pkt, s = args[:3]
+        if phantom_mode(pkt):
+            if get_or_add:
+                return s, self.phantom_value
+            return s
+        return f(*args)
+    return wrapper
+
+class SigAndHashAlgField(EnumField):
+    """
+    Used in _TLSSignature.
+    """
+    phantom_value = None
+    getfield = phantom_decorate(EnumField.getfield, True)
+    addfield = phantom_decorate(EnumField.addfield, False)
+
+class SigAndHashAlgsLenField(FieldLenField):
+    """
+    Used in TLS_Ext_SignatureAlgorithms and TLSCertificateResquest.
+    """
+    phantom_value = 0
+    getfield = phantom_decorate(FieldLenField.getfield, True)
+    addfield = phantom_decorate(FieldLenField.addfield, False)
+
+class SigAndHashAlgsField(FieldListField):
+    """
+    Used in TLS_Ext_SignatureAlgorithms and TLSCertificateResquest.
+    """
+    phantom_value = []
+    getfield = phantom_decorate(FieldListField.getfield, True)
+    addfield = phantom_decorate(FieldListField.addfield, False)
+
+
+class _TLSSignature(_GenericTLSSessionInheritance):
+    """
+    Prior to TLS 1.2, digitally-signed structure implictly used the
+    concatenation of a SHA-1 hash and a MD5 hash (this is the 'tls' mode
+    of key signing). TLS 1.2 introduced explicit SignatureAndHashAlgorithms,
+    i.e. couples of (hash_alg, sig_alg). See RFC 5246, section 7.4.1.4.1.
+
+    By default, the _TLSSignature implements the TLS 1.2 scheme,
+    but if it is provided a TLS context with a tls_version < 0x0303
+    at initialization, it will fall back to the implicit signature.
+
+    #XXX 'sig_alg' should be set in __init__ depending on the context.
+    """
+    name = "TLS Digital Signature"
+    fields_desc = [ SigAndHashAlgField("sig_alg", 0x0401, _tls_hash_sig),
+                    FieldLenField("sig_len", None, fmt="!H",
+                                  length_of="sig_val"),
+                    StrLenField("sig_val", None,
+                                length_from = lambda pkt: pkt.sig_len) ]
+
+    def __init__(self, *args, **kargs):
+        _GenericTLSSessionInheritance.__init__(self, *args, **kargs)
+        if ("tls_session" in kargs and
+            kargs["tls_session"].tls_version and
+            kargs["tls_session"].tls_version < 0x0303):
+            self.sig_alg = None
+
+    def _update_sig(self, m, key):
+        """
+        Sign 'm' with the PrivKey 'key' and update our own 'sig_val'.
+        Note that, even when 'sig_alg' is not None, we use the signature scheme
+        of the PrivKey (neither do we care to compare the both of them).
+        """
+        if self.sig_alg is None:
+            self.sig_val = key.sign(m, t='pkcs', h='tls')
+        else:
+            h = _tls_hash_sig[self.sig_alg].split('+')[0]
+            self.sig_val = key.sign(m, t='pkcs', h=h)
+
+    def _verify_sig(self, m, cert):
+        """
+        Verify that our own 'sig_val' carries the signature of 'm' by the
+        key associated to the Cert 'cert'.
+        """
+        if self.sig_val:
+            if self.sig_alg:
+                h = _tls_hash_sig[self.sig_alg].split('+')[0]
+                return cert.verify(m, self.sig_val, t='pkcs', h=h)
+            else:
+                return cert.verify(m, self.sig_val, t='pkcs', h='tls')
+        return False
+
+    def guess_payload_class(self, p):
+        return Padding
+
+class _TLSSignatureField(PacketField):
+    """
+    Used for 'digitally-signed struct' in several ServerKeyExchange,
+    and also in CertificateVerify. We can handle the anonymous case.
+    """
+    __slots__ = ["length_from"]
+    def __init__(self, name, default, length_from=None, remain=0):
+        self.length_from = length_from
+        PacketField.__init__(self, name, default, _TLSSignature, remain=remain)
+
+    def m2i(self, pkt, m):
+        l = self.length_from(pkt)
+        if l == 0:
+           return None
+        return _TLSSignature(m, tls_session=pkt.tls_session)
+
+
+class _TLSServerParamsField(PacketField):
+    """
+    This is a dispatcher for the Server*DHParams below, used in
+    TLSServerKeyExchange and based on the key_exchange.server_kx_msg_cls.
+    When this cls is None, it means that we should not see a ServerKeyExchange,
+    so we grab everything within length_from and make it available using Raw.
+
+    When the context has not been set (e.g. when no ServerHello was parsed or
+    dissected beforehand), we (kinda) clumsily set the cls by trial and error.
+    XXX We could use Serv*DHParams.check_params() once it has been implemented.
+    """
+    __slots__ = ["length_from"]
+    def __init__(self, name, default, length_from=None, remain=0):
+        self.length_from = length_from
+        PacketField.__init__(self, name, default, None, remain=remain)
+
+    def m2i(self, pkt, m):
+        s = pkt.tls_session
+        l = self.length_from(pkt)
+        if s.prcs:
+            cls = s.prcs.key_exchange.server_kx_msg_cls(m)
+            if cls is None:
+                return None, Raw(m[:l])/Padding(m[l:])
+            return cls(m, tls_session=s)
+        else:
+            try:
+                p = ServerDHParams(m, tls_session=s)
+                if pkcs_os2ip(p.load[:2]) not in _tls_hash_sig:
+                    raise Exception
+                return p
+            except:
+                cls = _tls_server_ecdh_cls_guess(m)
+                p = cls(m, tls_session=s)
+                if pkcs_os2ip(p.load[:2]) not in _tls_hash_sig:
+                    return None, Raw(m[:l])/Padding(m[l:])
+                return p
+
+
+###############################################################################
+### Server Key Exchange parameters & value                                  ###
+###############################################################################
+
+### Finite Field Diffie-Hellman
+
+class ServerDHParams(_GenericTLSSessionInheritance):
+    """
+    ServerDHParams for FFDH-based key exchanges,
+    as it is defined in RFC 5246, section 7.4.3.
+
+    Either with .fill_missing() or .post_dissection(), the server_kx_params and
+    client_kx_params of the TLS context are updated according to the
+    parsed/assembled values. It is the user's responsibility to store and
+    restore the original values if he wants to keep them. For instance, this
+    could be done between the writing of a ServerKeyExchange and the receiving
+    of a ClientKeyExchange (which includes secret generation).
+    """
+    name = "Server FFDH parameters"
+    fields_desc = [ FieldLenField("dh_plen", None, length_of="dh_p"),
+                    StrLenField("dh_p", "",
+                                length_from=lambda pkt: pkt.dh_plen),
+                    FieldLenField("dh_glen", None, length_of="dh_g"),
+                    StrLenField("dh_g", "",
+                                length_from=lambda pkt: pkt.dh_glen),
+                    FieldLenField("dh_Yslen", None, length_of="dh_Ys"),
+                    StrLenField("dh_Ys", "",
+                                length_from=lambda pkt: pkt.dh_Yslen) ]
+
+    def fill_missing(self):
+        """
+        We do not want TLSServerKeyExchange.build() to overload and recompute
+        things everytime it is called. This method can be called specifically
+        to have things filled in a smart fashion.
+
+        Note that we do not expect dh_params_def.g to be more than 0xff.
+        """
+        s = self.tls_session
+
+        default_params = FFDH_GROUPS['modp2048'][0].parameter_numbers()
+        default_mLen = FFDH_GROUPS['modp2048'][1]
+
+        if self.dh_p is "":
+            self.dh_p = pkcs_i2osp(default_params.p, default_mLen/8)
+        if self.dh_plen is None:
+            self.dh_plen = len(self.dh_p)
+
+        if self.dh_g is "":
+            self.dh_g = pkcs_i2osp(default_params.g, 1)
+        if self.dh_glen is None:
+            self.dh_glen = 1
+
+        p = pkcs_os2ip(self.dh_p)
+        g = pkcs_os2ip(self.dh_g)
+        real_params = dh.DHParameterNumbers(p, g).parameters(default_backend())
+
+        if self.dh_Ys is "":
+            s.server_kx_privkey = real_params.generate_private_key()
+            pubkey = s.server_kx_privkey.public_key()
+            y = pubkey.public_numbers().y
+            self.dh_Ys = pkcs_i2osp(y, pubkey.key_size/8)
+        # else, we assume that the user wrote the server_kx_privkey by himself
+        if self.dh_Yslen is None:
+            self.dh_Yslen = len(self.dh_Ys)
+
+        if not s.client_kx_ffdh_params:
+            s.client_kx_ffdh_params = real_params
+
+    def post_dissection(self, r):
+        """
+        XXX Check that the pubkey received is in the group.
+        """
+        #if self.dh_g and self.dh_p and self.dh_Ys: #XXX remove this, probably
+        p = pkcs_os2ip(self.dh_p)
+        g = pkcs_os2ip(self.dh_g)
+        pn = dh.DHParameterNumbers(p, g)
+
+        y = pkcs_os2ip(self.dh_Ys)
+        public_numbers = dh.DHPublicNumbers(y, pn)
+
+        s = self.tls_session
+        s.server_kx_pubkey = public_numbers.public_key(default_backend())
+
+        if not s.client_kx_ffdh_params:
+            s.client_kx_ffdh_params = pn.parameters(default_backend())
+
+    def guess_payload_class(self, p):
+        """
+        The signature after the params gets saved as Padding.
+        This way, the .getfield() which _TLSServerParamsField inherits
+        from PacketField will return the signature remain as expected.
+        """
+        return Padding
+
+
+### Elliptic Curve Diffie-Hellman
+
+_tls_ec_curve_types = { 1: "explicit_prime",
+                        2: "explicit_char2",
+                        3: "named_curve" }
+
+_tls_named_curves = {  1: "sect163k1",  2: "sect163r1",  3: "sect163r2",
+                       4: "sect193r1",  5: "sect193r2",  6: "sect233k1",
+                       7: "sect233r1",  8: "sect239k1",  9: "sect283k1",
+                      10: "sect283r1", 11: "sect409k1", 12: "sect409r1",
+                      13: "sect571k1", 14: "sect571r1", 15: "secp160k1",
+                      16: "secp160r1", 17: "secp160r2", 18: "secp192k1",
+                      19: "secp192r1", 20: "secp224k1", 21: "secp224r1",
+                      22: "secp256k1", 23: "secp256r1", 24: "secp384r1",
+                      25: "secp521r1", 26: "brainpoolP256r1",
+                      27: "brainpoolP384r1", 28: "brainpoolP512r1",
+                      0xff01: "arbitrary_explicit_prime_curves",
+                      0xff02: "arbitrary_explicit_char2_curves"}
+
+_tls_ec_basis_types = { 0: "ec_basis_trinomial", 1: "ec_basis_pentanomial"}
+
+class ECCurvePkt(Packet):
+    name = "Elliptic Curve"
+    fields_desc = [ FieldLenField("alen", None, length_of="a", fmt="B"),
+                    StrLenField("a", "", length_from = lambda pkt: pkt.alen),
+                    FieldLenField("blen", None, length_of="b", fmt="B"),
+                    StrLenField("b", "", length_from = lambda pkt: pkt.blen) ]
+
+
+## Char2 Curves
+
+class ECTrinomialBasis(Packet):
+    name = "EC Trinomial Basis"
+    val = 0
+    fields_desc = [ FieldLenField("klen", None, length_of="k", fmt="B"),
+                    StrLenField("k", "", length_from = lambda pkt: pkt.klen) ]
+    def guess_payload_class(self, p):
+        return Padding
+
+class ECPentanomialBasis(Packet):
+    name = "EC Pentanomial Basis"
+    val = 1
+    fields_desc = [ FieldLenField("k1len", None, length_of="k1", fmt="B"),
+                    StrLenField("k1", "", length_from=lambda pkt: pkt.k1len),
+                    FieldLenField("k2len", None, length_of="k2", fmt="B"),
+                    StrLenField("k2", "", length_from=lambda pkt: pkt.k2len),
+                    FieldLenField("k3len", None, length_of="k3", fmt="B"),
+                    StrLenField("k3", "", length_from=lambda pkt: pkt.k3len) ]
+    def guess_payload_class(self, p):
+        return Padding
+
+_tls_ec_basis_cls = { 0: ECTrinomialBasis, 1: ECPentanomialBasis}
+
+class _ECBasisTypeField(ByteEnumField):
+    __slots__ = ["basis_type_of"]
+    def __init__(self, name, default, enum, basis_type_of, remain=0):
+        self.basis_type_of = basis_type_of
+        EnumField.__init__(self, name, default, enum, "B")
+
+    def i2m(self, pkt, x):
+        if x is None:
+            val = 0
+            fld,fval = pkt.getfield_and_val(self.basis_type_of)
+            x = fld.i2basis_type(pkt, fval)
+        return x
+
+class _ECBasisField(PacketField):
+    __slots__ = ["clsdict", "basis_type_from"]
+    def __init__(self, name, default, basis_type_from, clsdict, remain=0):
+        self.clsdict = clsdict
+        self.basis_type_from = basis_type_from
+        PacketField.__init__(self, name, default, None, remain=remain)
+
+    def m2i(self, pkt, m):
+        basis = self.basis_type_from(pkt)
+        cls = self.clsdict[basis]
+        return cls(m)
+
+    def i2basis_type(self, pkt, x):
+        val = 0
+        try:
+            val = x.val
+        except:
+            pass
+        return val
+
+
+## Distinct ECParameters
+##
+## To support the different ECParameters structures defined in Sect. 5.4 of
+## RFC 4492, we define 3 separates classes for implementing the 3 associated
+## ServerECDHParams: ServerECDHNamedCurveParams, ServerECDHExplicitPrimeParams
+## and ServerECDHExplicitChar2Params (support for this one is only partial).
+## The most frequent encounter of the 3 is (by far) ServerECDHNamedCurveParams.
+
+class ServerECDHExplicitPrimeParams(_GenericTLSSessionInheritance):
+    """
+    XXX We provide parsing abilities for ExplicitPrimeParams, but there is no
+    'cryptography' support, hence no context operations.
+    """
+    name = "Server ECDH parameters - Explicit Prime"
+    fields_desc = [ ByteEnumField("curve_type", 1, _tls_ec_curve_types),
+		    FieldLenField("plen", None, length_of="p", fmt="B"),
+		    StrLenField("p", "", length_from=lambda pkt: pkt.plen),
+                    PacketField("curve", None, ECCurvePkt),
+                    FieldLenField("baselen", None, length_of="base", fmt="B"),
+                    StrLenField("base", "",
+                                length_from=lambda pkt: pkt.baselen),
+		    FieldLenField("orderlen", None,
+                                  length_of="order", fmt="B"),
+		    StrLenField("order", "",
+                                length_from=lambda pkt: pkt.orderlen),
+		    FieldLenField("cofactorlen", None,
+                                  length_of="cofactor", fmt="B"),
+		    StrLenField("cofactor", "",
+                                length_from=lambda pkt: pkt.cofactorlen),
+                    FieldLenField("pointlen", None,
+                                  length_of="point", fmt="B"),
+                    StrLenField("point", "",
+                                length_from=lambda pkt: pkt.pointlen) ]
+
+    def fill_missing(self):
+        """
+        We do not want TLSServerKeyExchange.build() to overload and recompute
+        things everytime it is called. This method can be called specifically
+        to have things filled in a smart fashion.
+
+        XXX Note that if it is not set by the user, the cofactor will always
+        be 1. It is true for most, but not all, TLS elliptic curves.
+
+        XXX Try and create a curve with the 'cryptography' lib somehow,
+        extract the missing fields for filling, then set s.server_kx_privkey.
+        """
+        if self.curve_type is None:
+            self.curve_type = _tls_ec_curve_types["explicit_prime"]
+
+    def post_dissection(self, pkt):
+        """
+        XXX Store the server_kx_pubkey.
+        XXX Check that the pubkey received is on the curve.
+        """
+
+    def guess_payload_class(self, p):
+        return Padding
+
+
+class ServerECDHExplicitChar2Params(_GenericTLSSessionInheritance):
+    """
+    XXX We provide parsing abilities for Char2Params, but there is no
+    'cryptography' support, hence no context operations.
+    """
+    name = "Server ECDH parameters - Explicit Char2"
+    fields_desc = [ ByteEnumField("curve_type", 2, _tls_ec_curve_types),
+                    ShortField("m", None),
+                    _ECBasisTypeField("basis_type", None,
+                                      _tls_ec_basis_types, "basis"),
+                    _ECBasisField("basis", ECTrinomialBasis(),
+                                  lambda pkt: pkt.basis_type,
+                                  _tls_ec_basis_cls),
+                    PacketField("curve", ECCurvePkt(), ECCurvePkt),
+                    FieldLenField("baselen", None, length_of="base", fmt="B"),
+                    StrLenField("base", "",
+                                length_from = lambda pkt: pkt.baselen),
+                    ByteField("order", None),
+                    ByteField("cofactor", None),
+                    FieldLenField("pointlen", None,
+                                  length_of="point", fmt="B"),
+                    StrLenField("point", "",
+                                length_from = lambda pkt: pkt.pointlen) ]
+
+    def fill_missing(self):
+        """
+        We do not want TLSServerKeyExchange.build() to overload and recompute
+        things everytime it is called. This method can be called specifically
+        to have things filled in a smart fashion.
+        """
+        if self.curve_type is None:
+            self.curve_type = _tls_ec_curve_types["explicit_char2"]
+
+    def post_dissection(self, pkt):
+        """
+        XXX Store the server_kx_pubkey.
+        XXX Check that the pubkey received is in the group.
+        """
+        pass
+
+    def guess_payload_class(self, p):
+        return Padding
+
+
+class ServerECDHNamedCurveParams(_GenericTLSSessionInheritance):
+    name = "Server ECDH parameters - Named Curve"
+    fields_desc = [ ByteEnumField("curve_type", 3, _tls_ec_curve_types),
+                    ShortEnumField("named_curve", None, _tls_named_curves),
+                    FieldLenField("pointlen", None,
+                                  length_of="point", fmt="B"),
+                    StrLenField("point", None,
+                                length_from = lambda pkt: pkt.pointlen) ]
+
+    def fill_missing(self):
+        """
+        We do not want TLSServerKeyExchange.build() to overload and recompute
+        things everytime it is called. This method can be called specifically
+        to have things filled in a smart fashion.
+        XXX We should account for the point_format (before 'point' filling).
+        """
+        s = self.tls_session
+
+        if self.curve_type is None:
+            self.curve_type = _tls_ec_curve_types["named_curve"]
+
+        if self.named_curve is None:
+            curve = ec.SECP256R1()
+            s.server_kx_privkey = ec.generate_private_key(curve,
+                                                          default_backend())
+            curve_id = 0
+            for cid, name in _tls_named_curves.iteritems():
+                if name == curve.name:
+                    curve_id = cid
+                    break
+            self.named_curve = curve_id
+        else:
+            curve_name = _tls_named_curves.get(self.named_curve)
+            if curve_name is None:
+                # this fallback is arguable
+                curve = ec.SECP256R1()
+            else:
+                curve_cls = ec._CURVE_TYPES.get(curve_name)
+                if curve_cls is None:
+                    # this fallback is arguable
+                    curve = ec.SECP256R1()
+                else:
+                    curve = curve_cls()
+            s.server_kx_privkey = ec.generate_private_key(curve,
+                                                          default_backend())
+
+        if self.point is None:
+            pubkey = s.server_kx_privkey.public_key()
+            self.point = pubkey.public_numbers().encode_point()
+        # else, we assume that the user wrote the server_kx_privkey by himself
+        if self.pointlen is None:
+            self.pointlen = len(self.point)
+
+        if not s.client_kx_ecdh_params:
+            s.client_kx_ecdh_params = curve
+
+    def post_dissection(self, r):
+        """
+        XXX Support compressed point format.
+        XXX Check that the pubkey received is on the curve.
+        """
+        #point_format = 0
+        #if self.point[0] in ['\x02', '\x03']:
+        #    point_format = 1
+
+        #if self.named_curve and self.point: #XXX remove this, probably
+        curve_name = _tls_named_curves[self.named_curve]
+        curve = ec._CURVE_TYPES[curve_name]()
+        import_point = ec.EllipticCurvePublicNumbers.from_encoded_point
+        pubnum = import_point(curve, self.point)
+        s = self.tls_session
+        s.server_kx_pubkey = pubnum.public_key(default_backend())
+
+        if not s.client_kx_ecdh_params:
+            s.client_kx_ecdh_params = curve
+
+    def guess_payload_class(self, p):
+        return Padding
+
+
+_tls_server_ecdh_cls = { 1: ServerECDHExplicitPrimeParams,
+                         2: ServerECDHExplicitChar2Params,
+                         3: ServerECDHNamedCurveParams }
+
+def _tls_server_ecdh_cls_guess(m):
+    if not m:
+        return None
+    curve_type = ord(m[0])
+    return _tls_server_ecdh_cls.get(curve_type, None)
+
+
+### RSA Encryption (export)
+
+class ServerRSAParams(_GenericTLSSessionInheritance):
+    """
+    Defined for RSA_EXPORT kx : it enables servers to share RSA keys shorter
+    than their principal {>512}-bit key, when it is not allowed for kx.
+
+    This should not appear in standard RSA kx negotiation, as the key
+    has already been advertised in the Certificate message.
+    """
+    name = "Server RSA_EXPORT parameters"
+    fields_desc = [ FieldLenField("rsamodlen", None, length_of="rsamod"),
+                    StrLenField("rsamod", "",
+                                length_from = lambda pkt: pkt.rsamodlen),
+                    FieldLenField("rsaexplen", None, length_of="rsaexp"),
+                    StrLenField("rsaexp", "",
+                                length_from = lambda pkt: pkt.rsaexplen) ]
+
+    def fill_missing(self):
+        ext_k = rsa.generate_private_key(public_exponent=0x10001,
+                                         key_size=512,
+                                         backend=default_backend())
+        pem_k = ext_k.private_bytes(
+                        encoding=serialization.Encoding.PEM,
+                        format=serialization.PrivateFormat.TraditionalOpenSSL,
+                        encryption_algorithm=serialization.NoEncryption())
+        k = PrivKeyRSA(pem_k)
+        self.tls_session.server_tmp_rsa_key = k
+        pubNum = k.pubkey.public_numbers()
+
+        if self.rsamod is "":
+            self.rsamod = pkcs_i2osp(pubNum.n, k.pubkey.key_size/8)
+        if self.rsamodlen is None:
+            self.rsamodlen = len(self.rsamod)
+
+        rsaexplen = math.ceil(math.log(pubNum.e)/math.log(2)/8.)
+        if self.rsaexp is "":
+            self.rsaexp = pkcs_i2osp(pubNum.e, rsaexplen)
+        if self.rsaexplen is None:
+            self.rsaexplen = len(self.rsaexp)
+
+    def post_dissection(self, pkt):
+        mLen = self.rsamodlen
+        m    = self.rsamod
+        e    = self.rsaexp
+        self.tls_session.server_tmp_rsa_key = PubKeyRSA((e, m, mLen))
+
+    def guess_payload_class(self, p):
+        return Padding
+
+
+### Pre-Shared Key
+
+class ServerPSKParams(Packet):
+    """
+    XXX We provide some parsing abilities for ServerPSKParams, but the
+    context operations have not been implemented yet. See RFC 4279.
+    Note that we do not cover the (EC)DHE_PSK key exchange,
+    which should contain a Server*DHParams after 'psk_identity_hint'.
+    """
+    name = "Server PSK parameters"
+    fields_desc = [ FieldLenField("psk_identity_hint_len", None,
+                                  length_of="psk_identity_hint", fmt="!H"),
+                    StrLenField("psk_identity_hint", "",
+                        length_from=lambda pkt: pkt.psk_identity_hint_len) ]
+
+    def fill_missing(self):
+        """
+        We do not want TLSServerKeyExchange.build() to overload and recompute
+        things everytime it is called. This method can be called specifically
+        to have things filled in a smart fashion.
+        """
+        pass
+
+    def post_dissection(self, pkt):
+        pass
+
+    def guess_payload_class(self, p):
+        return Padding
+
+
+###############################################################################
+### Client Key Exchange value                                               ###
+###############################################################################
+
+### FFDH/ECDH
+
+class ClientDiffieHellmanPublic(_GenericTLSSessionInheritance):
+    """
+    If the user provides a value for dh_Yc attribute,
+    the pms and ms are set accordingly when .post_build() is called.
+
+    XXX As specified in 7.4.7.2. of RFC 4346, we should distinguish the needs
+    for implicit or explicit value depending on availability of DH parameters
+    in *client* certificate. For now we can only do ephemeral/explicit DH.
+    """
+    name = "Client DH Public Value"
+    fields_desc = [ FieldLenField("dh_Yclen", None, length_of="dh_Yc"),
+                    StrLenField("dh_Yc", "",
+                                length_from=lambda pkt: pkt.dh_Yclen) ]
+
+    def post_build(self, pkt, pay):
+        s = self.tls_session
+
+        if self.dh_Yc == "":
+            params = s.client_kx_ffdh_params
+            s.client_kx_privkey = params.generate_private_key()
+            pubkey = s.client_kx_privkey.public_key()
+            y = pubkey.public_numbers().y
+            self.dh_Yc = pkcs_i2osp(y, pubkey.key_size/8)
+        # else, we assume that the user wrote the client_kx_privkey by himself
+        if self.dh_Yclen is None:
+            self.dh_Yclen = len(self.dh_Yc)
+
+        if s.client_kx_privkey and s.server_kx_pubkey:
+            pms = s.client_kx_privkey.exchange(s.server_kx_pubkey)
+            s.pre_master_secret = pms
+            s.compute_ms_and_derive_keys()
+
+        return pkcs_i2osp(self.dh_Yclen, 2) + self.dh_Yc + pay
+
+    def post_dissection(self, m):
+        """
+        First we update the client DHParams. Then, we try to update the server
+        DHParams generated during Server*DHParams building, with the shared
+        secret. Finally, we derive the session keys and update the context.
+        """
+        s = self.tls_session
+
+        if s.client_kx_ffdh_params:
+            y = pkcs_os2ip(self.dh_Yc)
+            param_numbers = s.client_kx_ffdh_params.parameter_numbers()
+            public_numbers = dh.DHPublicNumbers(y, param_numbers)
+            s.client_kx_pubkey = public_numbers.public_key(default_backend())
+
+        if s.server_kx_privkey and s.client_kx_pubkey:
+            ZZ = s.server_kx_privkey.exchange(s.client_kx_pubkey)
+            s.pre_master_secret = ZZ
+            s.compute_ms_and_derive_keys()
+
+    def guess_payload_class(self, p):
+        return Padding
+
+class ClientECDiffieHellmanPublic(_GenericTLSSessionInheritance):
+    """
+    Note that the 'len' field is 1 byte longer than with the previous class.
+    """
+    name = "Client ECDH Public Value"
+    fields_desc = [ FieldLenField("ecdh_Yclen", None,
+                                  length_of="ecdh_Yc", fmt="B"),
+                    StrLenField("ecdh_Yc", "",
+                                length_from=lambda pkt: pkt.ecdh_Yclen)]
+
+    def post_build(self, pkt, pay):
+        s = self.tls_session
+
+        if self.ecdh_Yc == "":
+            params = s.client_kx_ecdh_params
+            s.client_kx_privkey = ec.generate_private_key(params,
+                                                          default_backend())
+            pubkey = s.client_kx_privkey.public_key()
+            x = pubkey.public_numbers().x
+            y = pubkey.public_numbers().y
+            self.ecdh_Yc = ("\x04" +
+                            pkcs_i2osp(x, params.key_size/8) +
+                            pkcs_i2osp(y, params.key_size/8))
+        # else, we assume that the user wrote the client_kx_privkey by himself
+        if self.ecdh_Yclen is None:
+            self.ecdh_Yclen = len(self.ecdh_Yc)
+
+        if s.client_kx_privkey and s.server_kx_pubkey:
+            pms = s.client_kx_privkey.exchange(ec.ECDH(), s.server_kx_pubkey)
+            s.pre_master_secret = pms
+            s.compute_ms_and_derive_keys()
+
+        return pkcs_i2osp(self.ecdh_Yclen, 1) + self.ecdh_Yc + pay
+
+    def post_dissection(self, m):
+        s = self.tls_session
+
+        if s.client_kx_ecdh_params:
+            import_point = ec.EllipticCurvePublicNumbers.from_encoded_point
+            pub_num = import_point(s.client_kx_ecdh_params, self.ecdh_Yc)
+            s.client_kx_pubkey = pub_num.public_key(default_backend())
+
+        if s.server_kx_privkey and s.client_kx_pubkey:
+            ZZ = s.server_kx_privkey.exchange(ec.ECDH(), s.client_kx_pubkey)
+            s.pre_master_secret = ZZ
+            s.compute_ms_and_derive_keys()
+
+
+### RSA Encryption (standard & export)
+
+class EncryptedPreMasterSecret(_GenericTLSSessionInheritance):
+    """
+    Pay attention to implementation notes in section 7.4.7.1 of RFC 5246.
+    """
+    name = "RSA Encrypted PreMaster Secret"
+    fields_desc = [ _TLSClientVersionField("client_version", None,
+                                           _tls_version),
+                    StrFixedLenField("random", None, 46) ]
+
+    def pre_dissect(self, m):
+        s = self.tls_session
+        tbd = m
+        if s.tls_version >= 0x0301:
+            if len(m) < 2:      # Should not happen
+                return m
+            l = struct.unpack("!H", m[:2])[0]
+            if len(m) != l+2:
+                err = "TLS 1.0+, but RSA Encrypted PMS with no explicit length"
+                warning(err)
+            else:
+                tbd = m[2:]
+        if s.server_tmp_rsa_key is not None:
+            # priority is given to the tmp_key, if there is one
+            decrypted = s.server_tmp_rsa_key.decrypt(tbd)
+            pms = decrypted[-48:]
+        elif s.server_rsa_key is not None:
+            decrypted = s.server_rsa_key.decrypt(tbd)
+            pms = decrypted[-48:]
+        else:
+            pms = "\x00"*48     # Hack but we should not be there anyway
+            err = "No server RSA key to decrypt Pre Master Secret. Skipping."
+            warning(err)
+
+        s.pre_master_secret = pms
+        s.compute_ms_and_derive_keys()
+
+        return pms
+
+    def post_build(self, pkt, pay):
+        """
+        We encrypt the premaster secret (the 48 bytes) with either the server
+        certificate or the temporary RSA key provided in a server key exchange
+        message. After that step, we add the 2 bytes to provide the length, as
+        described in implementation notes at the end of section 7.4.7.1.
+        """
+        enc = pkt
+
+        s = self.tls_session
+        s.pre_master_secret = enc
+        s.compute_ms_and_derive_keys()
+
+        if s.server_tmp_rsa_key is not None:
+            enc = s.server_tmp_rsa_key.encrypt(pkt, "pkcs")
+        elif s.server_certs is not None and len(s.server_certs) > 0:
+            enc = s.server_certs[0].encrypt(pkt, "pkcs")
+        else:
+            warning("No material to encrypt Pre Master Secret")
+
+        l = ""
+        if s.tls_version >= 0x0301:
+            l = struct.pack("!H", len(enc))
+        return "%s%s%s" % (l, enc, pay)
+
+    def guess_payload_class(self, p):
+        return Padding
+
+
+# Pre-Shared Key
+
+class ClientPSKIdentity(Packet):
+    """
+    XXX We provide parsing abilities for ServerPSKParams, but the context
+    operations have not been implemented yet. See RFC 4279.
+    Note that we do not cover the (EC)DHE_PSK nor the RSA_PSK key exchange,
+    which should contain either an EncryptedPMS or a ClientDiffieHellmanPublic.
+    """
+    name = "Server PSK parameters"
+    fields_desc = [ FieldLenField("psk_identity_len", None,
+                                  length_of="psk_identity", fmt="!H"),
+                    StrLenField("psk_identity", "",
+                        length_from=lambda pkt: pkt.psk_identity_len) ]
+
diff --git a/scapy/layers/tls/record.py b/scapy/layers/tls/record.py
new file mode 100644
index 0000000000000000000000000000000000000000..cebe3c21d38d551bb22d23268cc385a098946a3e
--- /dev/null
+++ b/scapy/layers/tls/record.py
@@ -0,0 +1,664 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+Common TLS fields & bindings.
+
+This module covers the record layer, along with the ChangeCipherSpec, Alert and
+ApplicationData submessages. For the Handshake type, see tls_handshake.py.
+
+See the TLS class documentation for more information.
+"""
+
+import struct
+
+from scapy.config import conf
+from scapy.fields import *
+from scapy.packet import *
+from scapy.layers.inet import TCP
+from scapy.layers.tls.session import _GenericTLSSessionInheritance
+from scapy.layers.tls.handshake import _tls_handshake_cls, _TLSHandshake
+from scapy.layers.tls.basefields import (_TLSVersionField, _tls_version,
+                                         _TLSIVField, _TLSMACField,
+                                         _TLSPadField, _TLSPadLenField,
+                                         _TLSLengthField, _tls_type)
+from scapy.layers.tls.crypto.pkcs1 import randstring, pkcs_i2osp
+from scapy.layers.tls.crypto.compression import Comp_NULL
+from scapy.layers.tls.crypto.cipher_aead import AEADTagError
+from scapy.layers.tls.crypto.cipher_stream import Cipher_NULL
+from scapy.layers.tls.crypto.ciphers import CipherError
+from scapy.layers.tls.crypto.h_mac import HMACError
+
+
+###############################################################################
+### TLS Record Protocol                                                     ###
+###############################################################################
+
+class _TLSEncryptedContent(Raw):
+    """
+    When the content of a TLS record (more precisely, a TLSCiphertext) could
+    not be deciphered, we use this class to represent the encrypted data.
+    The MAC will still be parsed from the whole message, even though it could
+    not been verified. When present (depending on cipher type and protocol
+    version), the nonce_explicit, IV and/or padding will also be parsed.
+    """
+    name = "Encrypted Content"
+
+
+class _TLSMsgListField(PacketListField):
+    """
+    This is the actual content of the TLS record. As a TLS record may pack
+    multiple sublayer messages (notably, several handshake messages),
+    we inherit from PacketListField.
+    """
+    def __init__(self, name, default, length_from=None):
+        PacketListField.__init__(self, name, default, cls=None,
+                                 length_from=length_from)
+
+    def m2i(self, pkt, m):
+        """
+        Try to parse one of the TLS subprotocols (ccs, alert, handshake or
+        application_data). This is used inside a loop managed by .getfield().
+        """
+        cls = Raw
+        if pkt.type == 22:
+            if len(m) >= 1:
+                msgtype = ord(m[0])
+                cls = _tls_handshake_cls.get(msgtype, Raw)
+        elif pkt.type == 20:
+            cls = TLSChangeCipherSpec
+        elif pkt.type == 21:
+            cls = TLSAlert
+        elif pkt.type == 23:
+            cls = TLSApplicationData
+
+        if cls is Raw:
+            return Raw(m)
+        else:
+            return cls(m, tls_session=pkt.tls_session)
+
+    def getfield(self, pkt, s):
+        """
+        If the decryption of the content did not fail with a CipherError,
+        we begin a loop on the clear content in order to get as much messages
+        as possible, of the type advertised in the record header. This is
+        notably important for several TLS handshake implementations, which
+        may for instance pack a server_hello, a certificate, a
+        server_key_exchange and a server_hello_done, all in one record.
+        Each parsed message may update the TLS context throught their method
+        .post_dissection_tls_session_update().
+
+        If the decryption failed with a CipherError, presumably because we
+        missed the session keys, we signal it by returning a
+        _TLSEncryptedContent packet which simply contains the ciphered data.
+        """
+        l = self.length_from(pkt)
+        lst = []
+        ret = ""
+        remain = s
+        if l is not None:
+            remain, ret = s[:l], s[l:]
+
+        if pkt.decipherable:
+            if remain == "":
+                return ret, [TLSApplicationData(data="")]
+            while remain:
+                raw_msg = remain
+                p = self.m2i(pkt, remain)
+                if Padding in p:
+                    pad = p[Padding]
+                    remain = pad.load
+                    del(pad.underlayer.payload)
+                    if len(remain) != 0:
+                        raw_msg = raw_msg[:-len(remain)]
+                else:
+                    remain = ""
+
+                if not isinstance(p, Raw):
+                    p.post_dissection_tls_session_update(raw_msg)
+
+                lst.append(p)
+            return remain + ret, lst
+        else:
+            return ret, _TLSEncryptedContent(remain)
+
+    def i2m(self, pkt, p):
+       """
+       Update the context with information from the built packet.
+       If no type was given at the record layer, we try to infer it.
+       """
+       cur = ""
+       if isinstance(p, _GenericTLSSessionInheritance):
+           if pkt.type is None:
+               if isinstance(p, TLSChangeCipherSpec):
+                   pkt.type = 20
+               elif isinstance(p, TLSAlert):
+                   pkt.type = 21
+               elif isinstance(p, _TLSHandshake):
+                   pkt.type = 22
+               elif isinstance(p, TLSApplicationData):
+                   pkt.type = 23
+           p.tls_session = pkt.tls_session
+           cur = str(p)
+           p.post_build_tls_session_update(cur)
+       else:
+           cur = str(p)
+       return cur
+
+    def addfield(self, pkt, s, val):
+        """
+        Reconstruct the header because the TLS type may have been updated.
+        Then, append the content.
+        """
+        res = ""
+        for p in val:
+            res += self.i2m(pkt, p)
+        if not pkt.type:
+            pkt.type = 0
+        hdr = struct.pack("!B", pkt.type) + s[1:5]
+        return hdr + res
+
+
+class TLS(_GenericTLSSessionInheritance):
+    """
+    The generic TLS Record message, based on section 6.2 of RFC 5246.
+
+    When reading a TLS message, we try to parse as much as we can.
+    In .pre_dissect(), according to the type of the current cipher algorithm
+    (self.tls_session.rcs.cipher.type), we extract the 'iv', 'mac', 'pad' and
+    'padlen'. Some of these fields may remain blank: for instance, when using
+    a stream cipher, there is no IV nor any padding.
+
+    Once we have isolated the ciphered message aggregate (which should be one
+    or several TLS messages of the same type), we try to decipher it. Either we
+    succeed and store the clear data in 'msg', or we graciously fail with a
+    CipherError and store the ciphered data in 'msg'.
+
+    Unless the user manually provides the session secrets through the passing
+    of a 'tls_session', obviously the ciphered messages will not be deciphered.
+    Indeed, the need for a proper context may also present itself when trying
+    to parse clear handshake messages.
+
+    For instance, suppose you sniffed the beginning of a DHE-RSA negotiation:
+        t1 = TLS(<client_hello>)
+        t2 = TLS(<server_hello | certificate | server_key_exchange>)
+        t3 = TLS(<server_hello | certificate | server_key_exchange>,
+                 tls_session=t1.tls_session)
+    As no context was passed to t2, neither was any client_random. Hence scapy
+    will not be able to verify the signature of the server_key_exchange inside
+    t2. However, it should be able to do so for t3, thanks to the tls_session.
+    The consequence of not having a complete TLS context is even more obvious
+    when trying to parse ciphered content, as we decribed before.
+
+    Thus, in order to parse TLS-protected communications with scapy:
+    _either scapy reads every message from one side of the TLS connection and
+    builds every message from the other side (as such, it should know the
+    secrets needed for the generation of the pre_master_secret), while passing
+    the same tls_session context (this is how our automaton.py mostly works);
+    _or, if scapy did not build any TLS message, it has to create a TLS context
+    and feed it with secrets retrieved by whatever technique. Note that the
+    knowing the private key of the server certificate will not be sufficient
+    if a PFS ciphersuite was used. However, if you got a master_secret somehow,
+    use it with tls_session.(w|r)cs.derive_keys() and leave the rest to scapy.
+
+    When building a TLS message, we expect the tls_session to have the right
+    parameters for ciphering. Else, .post_build() might fail.
+    """
+    __slots__ = ["decipherable"]
+    name = "TLS"
+    fields_desc = [ ByteEnumField("type", None, _tls_type),
+                    _TLSVersionField("version", None, _tls_version),
+                    _TLSLengthField("len", None),
+                    _TLSIVField("iv", None),
+                    _TLSMsgListField("msg", None,
+                                     length_from=lambda pkt: pkt.len),
+                    _TLSMACField("mac", None),
+                    _TLSPadField("pad", None),
+                    _TLSPadLenField("padlen", None) ]
+
+    def __init__(self, *args, **kargs):
+        """
+        As long as 'decipherable' is True, _TLSMsgListField will try to
+        decipher the content of the TLS message. Else, it will simply
+        store/deliver the ciphered version.
+        """
+        self.decipherable = True
+        _GenericTLSSessionInheritance.__init__(self, *args, **kargs)
+
+
+    ### Parsing methods
+
+    def _tls_auth_decrypt(self, hdr, s):
+        """
+        Provided with the record header and AEAD-ciphered data, return the
+        sliced and clear tuple (nonce, TLSCompressed.fragment, mac). Note that
+        we still return the slicing of the original input in case of decryption
+        failure. Also, if the integrity check fails, a warning will be issued,
+        but we still return the sliced (unauthenticated) plaintext.
+        """
+        try:
+            read_seq_num = struct.pack("!Q", self.tls_session.rcs.seq_num)
+            self.tls_session.rcs.seq_num += 1
+            # self.type and self.version have not been parsed yet,
+            # this is why we need to look into the provided hdr.
+            add_data = read_seq_num + hdr[0] + hdr[1:3]
+            # Last two bytes of add_data are appended by the return function
+            return self.tls_session.rcs.cipher.auth_decrypt(add_data, s)
+        except CipherError as e:
+            self.decipherable = False
+            return e.args
+        except AEADTagError as e:
+            print "INTEGRITY CHECK FAILED"
+            return e.args
+
+    def _tls_decrypt(self, s):
+        """
+        Provided with stream- or block-ciphered data, return the clear version.
+        The cipher should have been updated with the right IV early on,
+        which should not be at the beginning of the input.
+        Note that we still return the slicing of the original input
+        in case of decryption failure.
+        """
+        try:
+            return self.tls_session.rcs.cipher.decrypt(s)
+        except CipherError as e:
+            self.decipherable = False
+            return e.args
+
+    def _tls_hmac_verify(self, hdr, msg, mac):
+        """
+        Provided with the record header, the TLSCompressed.fragment and the
+        HMAC, return True if the HMAC is correct. If we could not compute the
+        HMAC because the key was missing, there is no sense in verifying
+        anything, thus we also return True.
+
+        Meant to be used with a block cipher or a stream cipher.
+        It would fail with an AEAD cipher, because rcs.hmac would be None.
+        See RFC 5246, section 6.2.3.
+        """
+        mac_len = self.tls_session.rcs.mac_len
+        if mac_len == 0:            # should be TLS_NULL_WITH_NULL_NULL
+            return True
+        if len(mac) != mac_len:
+            return False
+
+        read_seq_num = struct.pack("!Q", self.tls_session.rcs.seq_num)
+        self.tls_session.rcs.seq_num += 1
+        alg = self.tls_session.rcs.hmac
+
+        version = struct.unpack("!H", hdr[1:3])[0]
+        try:
+            if version > 0x300:
+                h = alg.digest(read_seq_num + hdr + msg)
+            elif version == 0x300:
+                h = alg.digest_sslv3(read_seq_num + hdr[0] + hdr[3:5] + msg)
+            else:
+                raise Exception("Unrecognized version.")
+        except HMACError:
+            h = mac
+        return h == mac
+
+    def _tls_decompress(self, s):
+        """
+        Provided with the TLSCompressed.fragment,
+        return the TLSPlaintext.fragment.
+        """
+        alg = self.tls_session.rcs.compression
+        return alg.decompress(s)
+
+    def pre_dissect(self, s):
+        """
+        Decrypt, verify and decompress the message,
+        i.e. apply the previous methods according to the reading cipher type.
+        If the decryption was successful, 'len' will be the length of the
+        TLSPlaintext.fragment. Else, it should be the length of the
+        _TLSEncryptedContent.
+        """
+        if len(s) < 5:
+            raise Exception("Invalid record: header is too short.")
+
+        msglen = struct.unpack('!H', s[3:5])[0]
+        hdr, efrag, r = s[:5], s[5:5+msglen], s[msglen+5:]
+
+        iv = mac = pad = ""
+
+        cipher_type = self.tls_session.rcs.cipher.type
+
+        if cipher_type == 'block':
+            version = struct.unpack("!H", s[1:3])[0]
+
+            # Decrypt
+            if version >= 0x0302:
+                # Explicit IV for TLS 1.1 and 1.2
+                block_size = self.tls_session.rcs.cipher.block_size
+                iv, efrag = efrag[:block_size], efrag[block_size:]
+                self.tls_session.rcs.cipher.iv = iv
+                pfrag = self._tls_decrypt(efrag)
+                hdr = hdr[:3] + struct.pack("!H", len(pfrag))
+            else:
+                # Implicit IV for SSLv3 and TLS 1.0
+                pfrag = self._tls_decrypt(efrag)
+
+            # Excerpt below better corresponds to TLS 1.1 IV definition,
+            # but the result is the same as with TLS 1.2 anyway.
+            # This leading *IV* has been decrypted by _tls_decrypt with a
+            # random IV, hence it does not correspond to anything.
+            # What actually matters is that we got the first encrypted block
+            # in order to decrypt the second block (first data block).
+            #if version >= 0x0302:
+            #    block_size = self.tls_session.rcs.cipher.block_size
+            #    iv, pfrag = pfrag[:block_size], pfrag[block_size:]
+            #    l = struct.unpack('!H', hdr[3:5])[0]
+            #    hdr = hdr[:3] + struct.pack('!H', l-block_size)
+
+            # Extract padding ('pad' actually includes the trailing padlen)
+            padlen = ord(pfrag[-1]) + 1
+            mfrag, pad = pfrag[:-padlen], pfrag[-padlen:]
+
+            # Extract MAC
+            l = self.tls_session.rcs.mac_len
+            if l != 0:
+                cfrag, mac = mfrag[:-l], mfrag[-l:]
+            else:
+                cfrag, mac = mfrag, ""
+
+            # Verify integrity
+            hdr = hdr[:3] + struct.pack('!H', len(cfrag))
+            is_mac_ok = self._tls_hmac_verify(hdr, cfrag, mac)
+            if not is_mac_ok:
+                print "INTEGRITY CHECK FAILED"
+
+        elif cipher_type == 'stream':
+            # Decrypt
+            pfrag = self._tls_decrypt(efrag)
+            mfrag = pfrag
+
+            # Extract MAC
+            l = self.tls_session.rcs.mac_len
+            if l != 0:
+                cfrag, mac = mfrag[:-l], mfrag[-l:]
+            else:
+                cfrag, mac = mfrag, ""
+
+            # Verify integrity
+            hdr = hdr[:3] + struct.pack('!H', len(cfrag))
+            is_mac_ok = self._tls_hmac_verify(hdr, cfrag, mac)
+            if not is_mac_ok:
+                print "INTEGRITY CHECK FAILED"
+
+        elif cipher_type == 'aead':
+            # Authenticated encryption
+            # crypto/cipher_aead.py prints a warning for integrity failure
+            iv, cfrag, mac = self._tls_auth_decrypt(hdr, efrag)
+
+        if self.decipherable:
+            frag = self._tls_decompress(cfrag)
+        else:
+            frag = cfrag
+
+        reconstructed_body = iv + frag + mac + pad
+
+        l = len(frag)
+        # note that we do not include the MAC, only the content
+        hdr = hdr[:3] + struct.pack("!H", l)
+
+        return hdr + reconstructed_body + r
+
+    def post_dissect(self, s):
+        """
+        Commit the pending read state if it has been triggered.
+        We update nothing if the prcs was not set, as this probably means that
+        we're working out-of-context (and we need to keep the default rcs).
+        """
+        if self.tls_session.triggered_prcs_commit:
+            if self.tls_session.prcs is not None:
+                self.tls_session.rcs = self.tls_session.prcs
+                self.tls_session.prcs = None
+            self.tls_session.triggered_prcs_commit = False
+        return s
+
+    def do_dissect_payload(self, s):
+        """
+        Try to dissect the following data as a TLS message.
+        Note that overloading .guess_payload_class() would not be enough,
+        as the TLS session to be used would get lost.
+        """
+        if s:
+            try:
+                p = TLS(s, _internal=1, _underlayer=self,
+                        tls_session = self.tls_session)
+            except KeyboardInterrupt:
+                raise
+            except:
+                p = conf.raw_layer(s, _internal=1, _underlayer=self)
+            self.add_payload(p)
+
+
+    ### Building methods
+
+    def _tls_compress(self, s):
+        """
+        Provided with the TLSPlaintext.fragment,
+        return the TLSCompressed.fragment.
+        """
+        alg = self.tls_session.wcs.compression
+        return alg.compress(s)
+
+    def _tls_auth_encrypt(self, s):
+        """
+        Return the TLSCiphertext.fragment for AEAD ciphers, i.e. the whole
+        GenericAEADCipher. Also, the additional data is computed right here.
+        """
+        write_seq_num = struct.pack("!Q", self.tls_session.wcs.seq_num)
+        self.tls_session.wcs.seq_num += 1
+        add_data = (write_seq_num +
+                    pkcs_i2osp(self.type, 1) +
+                    pkcs_i2osp(self.version, 2) +
+                    pkcs_i2osp(len(s), 2))
+        return self.tls_session.wcs.cipher.auth_encrypt(s, add_data)
+
+    def _tls_hmac_add(self, hdr, msg):
+        """
+        Provided with the record header (concatenation of the TLSCompressed
+        type, version and length fields) and the TLSCompressed.fragment,
+        return the concatenation of the TLSCompressed.fragment and the HMAC.
+
+        Meant to be used with a block cipher or a stream cipher.
+        It would fail with an AEAD cipher, because wcs.hmac would be None.
+        See RFC 5246, section 6.2.3.
+        """
+        write_seq_num = struct.pack("!Q", self.tls_session.wcs.seq_num)
+        self.tls_session.wcs.seq_num += 1
+        alg = self.tls_session.wcs.hmac
+
+        version = struct.unpack("!H", hdr[1:3])[0]
+        if version > 0x300:
+            h = alg.digest(write_seq_num + hdr + msg)
+        elif version == 0x300:
+            h = alg.digest_sslv3(write_seq_num + hdr[0] + hdr[3:5] + msg)
+        else:
+            raise Exception("Unrecognized version.")
+        return msg + h
+
+    def _tls_pad(self, s):
+        """
+        Provided with the concatenation of the TLSCompressed.fragment and the
+        HMAC, append the right padding and return it as a whole.
+        This is the TLS-style padding: while SSL allowed for random padding,
+        TLS (misguidedly) specifies the repetition of the same byte all over,
+        and this byte must be equal to len(<entire padding>) - 1.
+
+        Meant to be used with a block cipher only.
+        """
+        padding = ""
+        block_size = self.tls_session.wcs.cipher.block_size
+        padlen = block_size - ((len(s) + 1) % block_size)
+        if padlen == block_size:
+            padlen = 0
+        pad_pattern = chr(padlen)
+        padding = pad_pattern * (padlen + 1)
+        return s + padding
+
+    def _tls_encrypt(self, s):
+        """
+        Return the stream- or block-ciphered version of the concatenated input.
+        In case of GenericBlockCipher, no IV has been specifically prepended to
+        the output, so this might not be the whole TLSCiphertext.fragment yet.
+        """
+        return self.tls_session.wcs.cipher.encrypt(s)
+
+    def post_build(self, pkt, pay):
+        """
+        Apply the previous methods according to the writing cipher type.
+        """
+        # Compute the length of TLSPlaintext fragment
+        hdr, frag = pkt[:5], pkt[5:]
+        l = len(frag)
+        hdr = hdr[:3] + struct.pack("!H", l)
+
+        # Compression
+        cfrag = self._tls_compress(frag)
+        l = len(cfrag)      # Update the length as a result of compression
+        hdr = hdr[:3] + struct.pack("!H", l)
+
+        cipher_type = self.tls_session.wcs.cipher.type
+
+        if cipher_type == 'block':
+            # Integrity
+            mfrag = self._tls_hmac_add(hdr, cfrag)
+
+            # Excerpt below better corresponds to TLS 1.1 IV definition,
+            # but the result is the same as with TLS 1.2 anyway.
+            #if self.version >= 0x0302:
+            #    l = self.tls_session.wcs.cipher.block_size
+            #    iv = randstring(l)
+            #    mfrag = iv + mfrag
+
+            # Add padding
+            pfrag = self._tls_pad(mfrag)
+
+            # Encryption
+            if self.version >= 0x0302:
+                # Explicit IV for TLS 1.1 and 1.2
+                l = self.tls_session.wcs.cipher.block_size
+                iv = randstring(l)
+                self.tls_session.wcs.cipher.iv = iv
+                efrag = self._tls_encrypt(pfrag)
+                efrag = iv + efrag
+            else:
+                # Implicit IV for SSLv3 and TLS 1.0
+                efrag = self._tls_encrypt(pfrag)
+
+        elif cipher_type == "stream":
+            # Integrity
+            mfrag = self._tls_hmac_add(hdr, cfrag)
+            # Encryption
+            efrag = self._tls_encrypt(mfrag)
+
+        elif cipher_type == "aead":
+            # Authenticated encryption (with nonce_explicit as header)
+            efrag = self._tls_auth_encrypt(cfrag)
+
+        # Now, we can commit pending write state if needed
+        # We update nothing if the pwcs was not set. This probably means that
+        # we're working out-of-context (and we need to keep the default wcs).
+        if self.tls_session.triggered_pwcs_commit:
+            if self.tls_session.pwcs is not None:
+                self.tls_session.wcs = self.tls_session.pwcs
+                self.tls_session.pwcs = None
+            self.tls_session.triggered_pwcs_commit = False
+
+        if self.len is not None:
+            # The user gave us a 'len', let's respect this ultimately
+            hdr = hdr[:3] + struct.pack("!H", self.len)
+        else:
+            # Update header with the length of TLSCiphertext.fragment
+            hdr = hdr[:3] + struct.pack("!H", len(efrag))
+
+        return hdr + efrag + pay
+
+
+###############################################################################
+### TLS ChangeCipherSpec                                                    ###
+###############################################################################
+
+_tls_changecipherspec_type = { 1: "change_cipher_spec" }
+
+class TLSChangeCipherSpec(_GenericTLSSessionInheritance):
+    """
+    Note that, as they are not handshake messages, the ccs messages do not get
+    appended to the list of messages whose integrity gets verified through the
+    Finished messages.
+    """
+    name = "TLS ChangeCipherSpec"
+    fields_desc = [ ByteEnumField("msgtype", 1, _tls_changecipherspec_type) ]
+
+    def post_dissection_tls_session_update(self, msg_str):
+        self.tls_session.triggered_prcs_commit = True
+
+    def post_build_tls_session_update(self, msg_str):
+        # Unlike for dissection case, we cannot commit pending write
+        # state as current write state. We need to delay this after
+        # the ChangeCipherSpec message has indeed been sent
+        self.tls_session.triggered_pwcs_commit = True
+
+
+###############################################################################
+### TLS Alert                                                               ###
+###############################################################################
+
+_tls_alert_level = { 1: "warning", 2: "fatal"}
+
+_tls_alert_description = {
+    0: "close_notify",                 10: "unexpected_message",
+    20: "bad_record_mac",              21: "decryption_failed",
+    22: "record_overflow",             30: "decompression_failure",
+    40: "handshake_failure",           41: "no_certificate_RESERVED",
+    42: "bad_certificate",             43: "unsupported_certificate",
+    44: "certificate_revoked",         45: "certificate_expired",
+    46: "certificate_unknown",         47: "illegal_parameter",
+    48: "unknown_ca",                  49: "access_denied",
+    50: "decode_error",                51: "decrypt_error",
+    60: "export_restriction_RESERVED", 70: "protocol_version",
+    71: "insufficient_security",       80: "internal_error",
+    90: "user_canceled",              100: "no_renegotiation",
+   110: "unsupported_extension",      111: "certificate_unobtainable",
+   112: "unrecognized_name",          113: "bad_certificate_status_response",
+   114: "bad_certificate_hash_value", 115: "unknown_psk_identity" }
+
+class TLSAlert(_GenericTLSSessionInheritance):
+    name = "TLS Alert"
+    fields_desc = [ ByteEnumField("level", None, _tls_alert_level),
+                    ByteEnumField("descr", None, _tls_alert_description) ]
+
+    def post_dissection_tls_session_update(self, msg_str):
+        pass
+
+    def post_build_tls_session_update(self, msg_str):
+        pass
+
+
+###############################################################################
+### TLS Application Data                                                    ###
+###############################################################################
+
+class TLSApplicationData(_GenericTLSSessionInheritance):
+    name = "TLS Application Data"
+    fields_desc = [ StrField("data", "") ]
+
+    def post_dissection_tls_session_update(self, msg_str):
+        pass
+
+    def post_build_tls_session_update(self, msg_str):
+        pass
+
+
+###############################################################################
+### Bindings                                                                ###
+###############################################################################
+
+bind_bottom_up(TCP, TLS, {"dport": 443})
+bind_bottom_up(TCP, TLS, {"sport": 443})
+
diff --git a/scapy/layers/tls/session.py b/scapy/layers/tls/session.py
new file mode 100644
index 0000000000000000000000000000000000000000..0c781552ccf1ef65e86f5465250331a4ca1c4019
--- /dev/null
+++ b/scapy/layers/tls/session.py
@@ -0,0 +1,577 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+TLS session handler.
+"""
+
+import random
+import socket
+import struct
+
+from scapy.config import conf
+from scapy.error import warning
+from scapy.packet import Packet
+from scapy.utils import repr_hex
+from scapy.layers.tls.crypto.compression import Comp_NULL
+from scapy.layers.tls.crypto.prf import PRF
+
+# Note the following import may happen inside connState.__init__()
+# in order to avoid to avoid cyclical dependancies.
+# from scapy.layers.tls.crypto.suites import TLS_NULL_WITH_NULL_NULL
+
+
+###############################################################################
+### Connection states                                                       ###
+###############################################################################
+
+class connState(object):
+    """
+    From RFC 5246, section 6.1:
+    A TLS connection state is the operating environment of the TLS Record
+    Protocol.  It specifies a compression algorithm, an encryption
+    algorithm, and a MAC algorithm.  In addition, the parameters for
+    these algorithms are known: the MAC key and the bulk encryption keys
+    for the connection in both the read and the write directions.
+    Logically, there are always four connection states outstanding: the
+    current read and write states, and the pending read and write states.
+    All records are processed under the current read and write states.
+    The security parameters for the pending states can be set by the TLS
+    Handshake Protocol, and the ChangeCipherSpec can selectively make
+    either of the pending states current, in which case the appropriate
+    current state is disposed of and replaced with the pending state; the
+    pending state is then reinitialized to an empty state.  It is illegal
+    to make a state that has not been initialized with security
+    parameters a current state.  The initial current state always
+    specifies that no encryption, compression, or MAC will be used.
+
+    These attributes and behaviours are mostly mapped in this class.
+    Also, note that scapy may make a current state out of a pending state
+    which has been initialized with dummy security parameters. We need
+    this in order to know when the content of a TLS message is encrypted,
+    whether we possess the right keys to decipher/verify it or not.
+    For instance, when scapy parses a CKE without knowledge of any secret,
+    and then a CCS, it needs to know that the following Finished
+    is encrypted and signed according to a new cipher suite, even though
+    it cannot decipher the message nor verify its integrity.
+    """
+
+    def __init__(self,
+                 connection_end="client",
+                 read_or_write="read",
+                 compression_alg=Comp_NULL,
+                 ciphersuite=None,
+                 tls_version=0x0303):
+
+        # It is the user's responsibility to keep the record seq_num
+        # under 2**64-1. If this value gets maxed out, the TLS class in
+        # record.py will crash when trying to encode it with struct.pack().
+        self.seq_num = 0
+
+        self.connection_end = connection_end
+        self.row = read_or_write
+
+        if ciphersuite is None:
+            from scapy.layers.tls.crypto.suites import TLS_NULL_WITH_NULL_NULL
+            ciphersuite = TLS_NULL_WITH_NULL_NULL
+
+        self.ciphersuite = ciphersuite(tls_version=tls_version)
+
+        self.compression = compression_alg()
+        self.key_exchange = ciphersuite.kx_alg()
+        self.prf = PRF(ciphersuite.hash_alg.name, tls_version)
+
+        # The attributes below usually get updated by .derive_keys()
+        # As discussed, we need to initialize cipher and mac with dummy values.
+
+        self.master_secret = None       # 48-byte shared secret
+        self.cipher_secret = None       # key for the symmetric cipher
+        self.mac_secret = None          # key for the MAC (stays None for AEAD)
+
+        self.cipher = ciphersuite.cipher_alg()
+
+        if ciphersuite.hmac_alg is None:        # AEAD
+            self.hmac = None
+            self.mac_len = self.cipher.tag_len
+        else:
+            self.hmac = ciphersuite.hmac_alg()
+            self.mac_len = self.hmac.hmac_len
+
+    def debug_repr(self, name, secret):
+        if conf.debug_tls and secret:
+            print "%s %s %s: %s" % (self.connection_end,
+                                    self.row,
+                                    name,
+                                    repr_hex(secret))
+
+    def derive_keys(self,
+                    client_random="",
+                    server_random="",
+                    master_secret=""):
+
+        cs = self.ciphersuite
+        self.master_secret = master_secret
+
+        # Derive the keys according to the cipher type and protocol version
+        key_block = self.prf.derive_key_block(master_secret,
+                                              server_random,
+                                              client_random,
+                                              cs.key_block_len)
+
+        # When slicing the key_block, keep the right half of the material
+        skip_first = False
+        if ((self.connection_end == "client" and self.row == "read") or
+            (self.connection_end == "server" and self.row == "write")):
+            skip_first = True
+
+        pos = 0
+        cipher_alg = cs.cipher_alg
+
+        ### MAC secret (for block and stream ciphers)
+        if (cipher_alg.type == "stream") or (cipher_alg.type == "block"):
+            start = pos
+            if skip_first:
+                start += cs.hmac_alg.key_len
+            end = start + cs.hmac_alg.key_len
+            self.mac_secret = key_block[start:end]
+            self.debug_repr("mac_secret", self.mac_secret)
+            pos += 2*cs.hmac_alg.key_len
+        else:
+            self.mac_secret = None
+
+        ### Cipher secret
+        start = pos
+        if skip_first:
+            start += cipher_alg.key_len
+        end = start + cipher_alg.key_len
+        key = key_block[start:end]
+        if cs.kx_alg.export:
+            reqLen = cipher_alg.expanded_key_len
+            key = self.prf.postprocess_key_for_export(key,
+                                                      client_random,
+                                                      server_random,
+                                                      self.connection_end,
+                                                      self.row,
+                                                      reqLen)
+        self.cipher_secret = key
+        self.debug_repr("cipher_secret", self.cipher_secret)
+        pos += 2*cipher_alg.key_len
+
+        ### Implicit IV (for block and AEAD ciphers)
+        start = pos
+        if cipher_alg.type == "block":
+            if skip_first:
+                start += cipher_alg.block_size
+            end = start + cipher_alg.block_size
+        elif cipher_alg.type == "aead":
+            if skip_first:
+                start += cipher_alg.salt_len
+            end = start + cipher_alg.salt_len
+
+        ### Now we have the secrets, we can instantiate the algorithms
+        if cs.hmac_alg is None:         # AEAD
+            self.hmac = None
+            self.mac_len = cipher_alg.tag_len
+        else:
+            self.hmac = cs.hmac_alg(self.mac_secret)
+            self.mac_len = self.hmac.hmac_len
+
+        if cipher_alg.type == "stream":
+            cipher = cipher_alg(self.cipher_secret)
+        elif cipher_alg.type == "block":
+            # We set an IV every time, even though it does not matter for
+            # TLS 1.1+ as it requires an explicit IV. Indeed the cipher.iv
+            # would get updated in TLS.post_build() or TLS.pre_dissect().
+            iv = key_block[start:end]
+            if cs.kx_alg.export:
+                reqLen = cipher_alg.block_size
+                iv = self.prf.generate_iv_for_export(client_random,
+                                                     server_random,
+                                                     self.connection_end,
+                                                     self.row,
+                                                     reqLen)
+            cipher = cipher_alg(self.cipher_secret, iv)
+            self.debug_repr("block iv", iv)
+        elif cipher_alg.type == "aead":
+            salt = key_block[start:end]
+            nonce_explicit_init = 0
+            # If you ever wanted to set a random nonce_explicit, use this:
+            #exp_bit_len = cipher_alg.nonce_explicit_len * 8
+            #nonce_explicit_init = random.randint(0, 2**exp_bit_len - 1)
+            cipher = cipher_alg(self.cipher_secret, salt, nonce_explicit_init)
+            self.debug_repr("aead salt", salt)
+        self.cipher = cipher
+
+    def __repr__(self):
+        def indent(s):
+            if s and s[-1] == '\n':
+                s = s[:-1]
+            s = '\n'.join(map(lambda x: '\t'+x, s.split('\n')) + [''])
+            return s
+
+        res =  "Connection end : %s\n" % self.connection_end.upper()
+        res += "Cipher suite   : %s (0x%04x)\n" % (self.ciphersuite.name,
+                                                   self.ciphersuite.val)
+        res += "Compression Alg: %s (0x%02x)\n" % (self.compression.name,
+                                                   self.compression.val)
+        tabsize = 4
+        return res.expandtabs(tabsize)
+
+class readConnState(connState):
+    def __init__(self, **kargs):
+        connState.__init__(self, read_or_write="read", **kargs)
+
+class writeConnState(connState):
+    def __init__(self, **kargs):
+        connState.__init__(self, read_or_write="write", **kargs)
+
+
+###############################################################################
+### TLS session                                                             ###
+###############################################################################
+
+class tlsSession(object):
+    """
+    This is our TLS context, which gathers information from both sides of the
+    TLS connection. These sides are represented by a readConnState instance and
+    a writeConnState instance. Along with overarching network attributes, a
+    tlsSession object also holds negotiated, shared information, such as the
+    key exchange parameters and the master secret (when available).
+    """
+    def __init__(self,
+                 ipsrc=None, ipdst=None,
+                 sport=None, dport=None, sid=None,
+                 connection_end="client",
+                 wcs=None, rcs=None):
+
+        ### Network settings
+
+        self.ipsrc = ipsrc
+        self.ipdst = ipdst
+        self.sport = sport
+        self.dport = dport
+        self.sid = sid
+
+        # Our TCP socket. None until we send (or receive) a packet.
+        self.sock = None
+
+
+        ### Connection states
+
+        self.connection_end = connection_end
+
+        if wcs is None:
+            self.wcs = writeConnState(connection_end=connection_end)
+            self.wcs.derive_keys(client_random="",
+                                 server_random="",
+                                 master_secret="")
+        if rcs is None:
+            self.rcs = readConnState(connection_end=connection_end)
+            self.rcs.derive_keys(client_random="",
+                                 server_random="",
+                                 master_secret="")
+
+        # The pending write/read states are updated by the building/parsing
+        # of various TLS packets. They get committed to self.wcs/self.rcs
+        # once scapy builds/parses a ChangeCipherSpec message.
+        self.pwcs = None
+        self.triggered_pwcs_commit = False
+        self.prcs = None
+        self.triggered_prcs_commit = False
+
+
+        ### Certificates and private keys
+
+        # The server certificate chain, as a list of Cert instances.
+        # Either we act as server and it has to be provided, or it is expected
+        # to be sent by the server through a Certificate message.
+        # The server certificate should be self.server_certs[0].
+        self.server_certs = []
+
+        # The server private key, as a PrivKey instance, when acting as server.
+        # XXX It would be nice to be able to provide both an RSA and an ECDSA
+        # key in order for the same scapy server to support both families of
+        # cipher suites. See INIT_TLS_SESSION() in automaton.py.
+        # (For now server_key holds either one of both types for DHE
+        # authentication, while server_rsa_key is used only for RSAkx.)
+        self.server_key = None
+        self.server_rsa_key = None
+        #self.server_ecdsa_key = None
+
+        # Back in the dreadful EXPORT days, US servers were forbidden to use
+        # RSA keys longer than 512 bits for RSAkx. When their usual RSA key
+        # was longer than this, they had to create a new key and send it via
+        # a ServerRSAParams message. When receiving such a message,
+        # scapy stores this key in server_tmp_rsa_key as a PubKey instance.
+        self.server_tmp_rsa_key = None
+
+        # When client authentication is performed, we need at least a
+        # client certificate chain. If we act as client, we also have
+        # to provide the key associated with the first certificate.
+        self.client_certs = []
+        self.client_key = None
+
+
+        ### Ephemeral key exchange parameters
+
+        ## XXX Explain why we need pubkey (which should be contained in privkey)
+        # also, params is used to hold params between the SKE and the CKE
+        self.server_kx_privkey = None
+        self.server_kx_pubkey = None
+        self.client_kx_privkey = None
+        self.client_kx_pubkey = None
+
+        self.client_kx_ffdh_params = None
+        self.client_kx_ecdh_params = None
+
+        ## Either an instance of FFDHParams or ECDHParams.
+        ## Depending on which side of the connection we operate,
+        ## one of these params will not hold 'priv' and 'secret' attributes.
+        ## We did not use these intermediaries for RSAkx, as the 'priv' would
+        ## equate the PrivKey, and the 'secret' the pre_master_secret.
+        ## (It could have been useful for RSAkx export, though...)
+        #self.server_kx_params = None
+        #self.client_kx_params = None
+
+
+        ### Negotiated session parameters
+
+        # The advertised TLS version found in the ClientHello (and
+        # EncryptedPreMasterSecret if used). If acting as server, it is set to
+        # the value advertised by the client in its ClientHello.
+        #XXX See what needs to be changed in automaton.py in order to keep
+        # this to None. For now it is necessary for running the client.
+        self.advertised_tls_version = 0x303
+
+        # The agreed-upon TLS version found in the ServerHello.
+        self.tls_version = None
+
+        # These attributes should eventually be known to both sides.
+        self.client_random = None
+        self.server_random = None
+        self.pre_master_secret = None
+        self.master_secret = None
+
+        # Handshake messages needed for Finished computation/validation.
+        # No record layer headers, no HelloRequests, no ChangeCipherSpecs.
+        self.handshake_messages = []
+        self.handshake_messages_parsed = []
+
+        # All exchanged TLS packets.
+        self.exchanged_pkts = []
+
+
+    ### Master secret management
+
+    def compute_master_secret(self):
+        if self.pre_master_secret is None:
+            warning("Missing pre_master_secret while computing master_secret")
+        if self.client_random is None:
+            warning("Missing client_random while computing master_secret")
+        if self.server_random is None:
+            warning("Missing server_random while computing master_secret")
+
+        ms = self.pwcs.prf.compute_master_secret(self.pre_master_secret,
+                                                 self.client_random,
+                                                 self.server_random)
+        self.master_secret = ms
+        if conf.debug_tls:
+            print "master secret: %s" % repr_hex(ms)
+
+    def compute_ms_and_derive_keys(self):
+        self.compute_master_secret()
+        self.prcs.derive_keys(client_random=self.client_random,
+                              server_random=self.server_random,
+                              master_secret=self.master_secret)
+        self.pwcs.derive_keys(client_random=self.client_random,
+                              server_random=self.server_random,
+                              master_secret=self.master_secret)
+
+
+    ### Tests for record building/parsing
+
+    def consider_read_padding(self):
+        # Return True if padding is needed. Used by TLSPadField.
+        return self.rcs.cipher.type == "block"
+
+    def consider_write_padding(self):
+        # Return True if padding is needed. Used by TLSPadField.
+        return self.wcs.cipher.type == "block"
+
+    def use_explicit_iv(self, version, cipher_type):
+        # Return True if an explicit IV is needed. Required for TLS 1.1+
+        # when either a block or an AEAD cipher is used.
+        if cipher_type == "stream":
+            return False
+        return version >= 0x0302
+
+
+    ### Python object management
+
+    def hash(self):
+        s1 = struct.pack("!H", self.sport)
+        s2 = struct.pack("!H", self.dport)
+        family = socket.AF_INET
+        if ':' in self.ipsrc:
+            family = socket.AF_INET6
+        s1 += socket.inet_pton(family, self.ipsrc)
+        s2 += socket.inet_pton(family, self.ipdst)
+        return strxor(s1, s2)
+
+    def eq(self, other):
+        ok = False
+        if (self.sport == other.sport and self.dport == other.dport and
+            self.ipsrc == other.ipsrc and self.ipdst == other.ipdst):
+            ok = True
+
+        if (not ok and
+            self.dport == other.sport and self.sport == other.dport and
+            self.ipdst == other.ipsrc and self.ipsrc == other.ipdst):
+            ok = True
+
+        if ok:
+            if self.sid and other.sid:
+                return self.sid == other.sid
+            return True
+
+        return False
+
+    def __repr__(self):
+        sid = repr(self.sid)
+        if len(sid) > 12:
+            sid = sid[:11] + "..."
+        return "%s:%s > %s:%s" % (self.ipsrc, str(self.sport),
+                                  self.ipdst, str(self.dport))
+
+
+###############################################################################
+### Session singleton                                                       ###
+###############################################################################
+
+class _GenericTLSSessionInheritance(Packet):
+    """
+    Many classes inside the TLS module need to get access to session-related
+    information. For instance, an encrypted TLS record cannot be parsed without
+    some knowledge of the cipher suite being used and the secrets which have
+    been negotiated. Passing information is also essential to the handshake.
+    To this end, various TLS objects inherit from the present class.
+    """
+    __slots__ = ["tls_session"]
+    name = "Dummy Generic TLS Packet"
+    fields_desc = []
+
+    def __init__(self, _pkt="", post_transform=None, _internal=0,
+                 _underlayer=None, tls_session=None, **fields):
+        try:
+            setme = self.tls_session is None
+        except:
+            setme = True
+
+        if setme:
+            if tls_session is None:
+                self.tls_session = tlsSession()
+            else:
+                self.tls_session = tls_session
+
+        Packet.__init__(self, _pkt=_pkt, post_transform=post_transform,
+                        _internal=_internal, _underlayer=_underlayer,
+                        **fields)
+
+    def tls_session_update(self, msg_str):
+        """
+        post_{build, dissection}_tls_session_update() are used to update the
+        tlsSession context. The default definitions below, along with
+        tls_session_update(), may prevent code duplication in some cases.
+        """
+        pass
+
+    def post_build_tls_session_update(self, msg_str):
+        self.tls_session_update(msg_str)
+
+    def post_dissection_tls_session_update(self, msg_str):
+        self.tls_session_update(msg_str)
+
+    def copy(self):
+        pkt = Packet.copy(self)
+        pkt.tls_session = self.tls_session
+        return pkt
+
+    def clone_with(self, payload=None, **kargs):
+        pkt = Packet.clone_with(self, payload=payload, **kargs)
+        pkt.tls_session = self.tls_session
+        return pkt
+
+    def show2(self):
+        """
+        Rebuild the TLS packet with the same context, and then .show() it.
+        We need self.__class__ to call the subclass in a dynamic way.
+        """
+        self.__class__(str(self), tls_session=self.tls_session).show()
+
+    # Uncomment this when the automata update IPs and ports properly
+    #def mysummary(self):
+    #    return "TLS %s" % repr(self.tls_session)
+
+
+###############################################################################
+### Multiple TLS sessions                                                   ###
+###############################################################################
+
+class _tls_sessions(object):
+    def __init__(self):
+        self.sessions = {}
+
+    def add(self, session):
+        s = self.find(session)
+        if s:
+            print "TLS session already exists. Not adding..."
+            return
+
+        h = session.hash()
+        if self.sessions.has_key(h):
+            self.sessions[h].append(session)
+        else:
+            self.sessions[h] = [session]
+
+    def rem(self, session):
+        s = self.find(session)
+        if s:
+            print "TLS session does not exist. Not removing..."
+            return
+
+        h = session.hash()
+        self.sessions[h].remove(session)
+
+    def find(self, session):
+        h = session.hash()
+        if self.sessions.has_key(h):
+            for k in self.sessions[h]:
+                if k.eq(session):
+                    if conf.tls_verbose:
+                        print "Found Matching session %s" % k
+                    return k
+        if conf.tls_verbose:
+            print "Did not find matching session %s" % session
+        return None
+
+    def __repr__(self):
+        res = [("First endpoint", "Second endpoint", "Session ID")]
+        for l in self.sessions.values():
+            for s in l:
+                src = "%s[%d]" % (s.ipsrc, s.sport)
+                dst = "%s[%d]" % (s.ipdst, s.dport)
+                sid = repr(s.sid)
+                if len(sid) > 12:
+                    sid = sid[:11] + "..."
+                res.append((src, dst, sid))
+        colwidth = map(lambda x: max(map(lambda y: len(y), x)),
+                       apply(zip, res))
+        fmt = "  ".join(map(lambda x: "%%-%ds"%x, colwidth))
+        return "\n".join(map(lambda x: fmt % x, res))
+
+
+conf.tls_sessions = _tls_sessions()
+conf.tls_verbose = False
+
diff --git a/scapy/layers/tls/tools.py b/scapy/layers/tls/tools.py
new file mode 100644
index 0000000000000000000000000000000000000000..921e669ce735987b93c62e82c7b5aca860c17e71
--- /dev/null
+++ b/scapy/layers/tls/tools.py
@@ -0,0 +1,211 @@
+## This file is part of Scapy
+## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
+##                     2015, 2016 Maxence Tury
+## This program is published under a GPLv2 license
+
+"""
+TLS helpers, provided as out-of-context methods.
+"""
+
+from scapy.error import warning
+from scapy.fields import (ByteEnumField, ShortEnumField,
+                          FieldLenField, StrLenField)
+from scapy.packet import Packet
+
+from scapy.layers.tls.basefields import _tls_type, _tls_version
+
+
+class TLSPlaintext(Packet):
+    name = "TLS Plaintext"
+    fields_desc = [ ByteEnumField("type", None, _tls_type),
+                    ShortEnumField("version", None, _tls_version),
+                    FieldLenField("len", None, length_of="fragment",
+                                  fmt="!H"),
+                    StrLenField("fragment", "",
+                                length_from = lambda pkt: pkt.length) ]
+
+class TLSCompressed(TLSPlaintext):
+    name = "TLS Compressed"
+
+class TLSCiphertext(TLSPlaintext):
+    name = "TLS Ciphertext"
+
+
+def _tls_compress(alg, p):
+    """
+    Compress p (a TLSPlaintext instance) using compression algorithm instance
+    alg and return a TLSCompressed instance.
+    """
+    c = TLSCompressed()
+    c.type = p.type
+    c.version = p.version
+    c.fragment = alg.compress(p.fragment)
+    c.len = len(c.fragment)
+    return c
+
+def _tls_decompress(alg, c):
+    """
+    Decompress c (a TLSCompressed instance) using compression algorithm
+    instance alg and return a TLSPlaintext instance.
+    """
+    p = TLSPlaintext()
+    p.type = c.type
+    p.version = c.version
+    p.fragment = alg.decompress(c.fragment)
+    p.len = len(p.fragment)
+    return p
+
+def _tls_mac_add(alg, c, write_seq_num):
+    """
+    Compute the MAC using provided MAC alg instance over TLSCiphertext c using
+    current write sequence number write_seq_num. Computed MAC is then appended
+    to c.fragment and c.length is updated to reflect that change. It is the
+    caller responsability to increment the sequence number after the operation.
+    The function has no return value.
+    """
+    write_seq_num = struct.pack("!Q", write_seq_num)
+    h = alg.digest(write_seq_num + str(c))
+    c.fragment += h
+    c.len += alg.hash_len
+
+def _tls_mac_verify(alg, p, read_seq_num):
+    """
+    Verify if the MAC in provided message (message resulting from decryption
+    and padding removal) is valid. Current read sequence number is used in
+    the verification process.
+
+    If the MAC is valid:
+     - The function returns True
+     - The packet p is updated in the following way: trailing MAC value is
+       removed from p.fragment and length is updated accordingly.
+
+    In case of error, False is returned, and p may have been modified.
+
+    Also note that it is the caller's responsibility to update the read
+    sequence number after the operation.
+    """
+    h_size = alg.hash_len
+    if p.len < h_size:
+        return False
+    received_h = p.fragment[-h_size:]
+    p.len -= h_size
+    p.fragment = p.fragment[:-h_size]
+
+    read_seq_num = struct.pack("!Q", read_seq_num)
+    h = alg.digest(read_seq_num + str(p))
+    return h == received_h
+
+def _tls_add_pad(p, block_size):
+    """
+    Provided with cipher block size parameter and current TLSCompressed packet
+    p (after MAC addition), the function adds required, deterministic padding
+    to p.fragment before encryption step, as it is defined for TLS (i.e. not
+    SSL and its allowed random padding). The function has no return value.
+    """
+    padlen = block_size - ((p.len + 1) % block_size)
+    if padlen == block_size:
+        padlen =  0
+    padding = chr(padlen) * (padlen + 1)
+    p.len += len(padding)
+    p.fragment += padding
+
+def _tls_del_pad(p):
+    """
+    Provided with a just decrypted TLSCiphertext (now a TLSPlaintext instance)
+    p, the function removes the trailing padding found in p.fragment. It also
+    performs some sanity checks on the padding (length, content, ...). False
+    is returned if one of the check fails. Otherwise, True is returned,
+    indicating that p.fragment and p.len have been updated.
+    """
+
+    if p.len < 1:
+        warning("Message format is invalid (padding)")
+        return False
+
+    padlen = ord(p.fragment[-1]) + 1
+    if (p.len < padlen):
+        warning("Invalid padding length")
+        return False
+
+    if (p.fragment[-padlen:] != p.fragment[-1] * padlen):
+        warning("Padding content is invalid %s" % repr(p.fragment[-padlen:]))
+        return False
+
+    p.fragment = p.fragment[:-padlen]
+    p.len -= padlen
+
+    return True
+
+def _tls_encrypt(alg, p):
+    """
+    Provided with an already MACed TLSCompressed packet, and a stream or block
+    cipher alg, the function converts it into a TLSCiphertext (i.e. encrypts it
+    and updates length). The function returns a newly created TLSCiphertext
+    instance.
+    """
+    c = TLSCiphertext()
+    c.type = p.type
+    c.version = p.version
+    c.fragment = alg.encrypt(p.fragment)
+    c.len = len(c.fragment)
+    return c
+
+def _tls_decrypt(alg, c):
+    """
+    Provided with a TLSCiphertext instance c, and a stream or block cipher alg,
+    the function decrypts c.fragment and returns a newly created TLSPlaintext.
+    """
+    p = TLSPlaintext()
+    p.type = c.type
+    p.version = c.version
+    p.fragment = alg.decrypt(c.fragment)
+    p.len = len(p.fragment)
+    return p
+
+def _tls_aead_auth_encrypt(alg, p, write_seq_num):
+    """
+    Provided with a TLSCompressed instance p, the function applies AEAD
+    cipher alg to p.fragment and builds a new TLSCiphertext instance. Unlike
+    for block and stream ciphers, for which the authentication step is done
+    separately, AEAD alg does it simultaneously: this is the reason why
+    write_seq_num is passed to the function, to be incorporated in
+    authenticated data. Note that it is the caller's responibility to increment
+    write_seq_num afterwards.
+    """
+    P = str(p)
+    write_seq_num = struct.pack("!Q", write_seq_num)
+    A = write_seq_num + P[:5]
+
+    c = TLCCiphertext()
+    c.type = p.type
+    c.version = p.version
+    c.fragment = alg.auth_encrypt(P, A)
+    c.len = len(c.fragment)
+    return c
+
+def _tls_aead_auth_decrypt(alg, c, read_seq_num):
+    """
+    Provided with a TLSCiphertext instance c, the function applies AEAD
+    cipher alg auth_decrypt function to c.fragment (and additional data)
+    in order to authenticate the data and decrypt c.fragment. When those
+    steps succeed, the result is a newly created TLSCompressed instance.
+    On error, None is returned. Note that it is the caller's responsibility to
+    increment read_seq_num afterwards.
+    """
+    # 'Deduce' TLSCompressed length from TLSCiphertext length
+    # There is actually no guaranty of this equality, but this is defined as
+    # such in TLS 1.2 specifications, and it works for GCM and CCM at least.
+    l = p.len - alg.nonce_explicit_len - alg.tag_len
+    read_seq_num = struct.pack("!Q", read_seq_num)
+    A = read_seq_num + struct.pack('!BHH', p.type, p.version, l)
+
+    p = TLSCompressed()
+    p.type = c.type
+    p.version = c.version
+    p.len = l
+    p.fragment = alg.auth_decrypt(A, c.fragment)
+
+    if p.fragment is None: # Verification failed.
+        return None
+    return p
+
diff --git a/scapy/layers/x509.py b/scapy/layers/x509.py
index ee14bc43d24ced4e00f6551d64bcb1df30e07171..b5b03c9b13724184a1799132c8a6a48dbd0c2cb1 100644
--- a/scapy/layers/x509.py
+++ b/scapy/layers/x509.py
@@ -16,6 +16,7 @@ from scapy.packet import Packet
 from scapy.fields import PacketField
 from scapy.volatile import *
 
+
 class ASN1P_OID(ASN1_Packet):
     ASN1_codec = ASN1_Codecs.BER
     ASN1_root = ASN1F_OID("oid", "0")
@@ -29,10 +30,10 @@ class ASN1P_PRIVSEQ(ASN1_Packet):
     # It showcases the private high-tag decoding capacities of scapy.
     ASN1_codec = ASN1_Codecs.BER
     ASN1_root = ASN1F_SEQUENCE(
-            ASN1F_IA5_STRING("str", ""),
-            ASN1F_STRING("int", 0),
-            explicit_tag=0,
-            flexible_tag=True)
+                    ASN1F_IA5_STRING("str", ""),
+                    ASN1F_STRING("int", 0),
+                    explicit_tag=0,
+                    flexible_tag=True)
 
 
 #######################
@@ -201,7 +202,7 @@ class X509_X400Address(ASN1_Packet):
     ASN1_codec = ASN1_Codecs.BER
     ASN1_root = ASN1F_field("x400Address", "")
 
-default_directoryName = [
+_default_directoryName = [
         X509_RDN(),
         X509_RDN(
             rdn=[X509_AttributeTypeAndValue(
@@ -215,7 +216,7 @@ default_directoryName = [
 
 class X509_DirectoryName(ASN1_Packet):
     ASN1_codec = ASN1_Codecs.BER
-    ASN1_root = ASN1F_SEQUENCE_OF("directoryName", default_directoryName,
+    ASN1_root = ASN1F_SEQUENCE_OF("directoryName", _default_directoryName,
                     X509_RDN)
 
 class X509_EDIPartyName(ASN1_Packet):
@@ -303,7 +304,7 @@ class X509_ExtDistributionPointName(ASN1_Packet):
     ASN1_root = ASN1F_CHOICE("distributionPointName", None,
                     X509_ExtFullName, X509_ExtNameRelativeToCRLIssuer)
 
-reasons_mapping = ["unused",
+_reasons_mapping = ["unused",
                    "keyCompromise",
                    "cACompromise",
                    "affiliationChanged",
@@ -322,14 +323,14 @@ class X509_ExtDistributionPoint(ASN1_Packet):
                                      X509_ExtDistributionPointName,
                                      explicit_tag=0xa0)),
                     ASN1F_optional(
-                        ASN1F_FLAGS("reasons", None, reasons_mapping,
+                        ASN1F_FLAGS("reasons", None, _reasons_mapping,
                                     implicit_tag=0x81)),
                     ASN1F_optional(
                         ASN1F_SEQUENCE_OF("cRLIssuer", None,
                                           X509_GeneralName,
                                           implicit_tag=0xa2)))
 
-ku_mapping = ["digitalSignature",
+_ku_mapping = ["digitalSignature",
               "nonRepudiation",
               "keyEncipherment",
               "dataEncipherment",
@@ -341,7 +342,7 @@ ku_mapping = ["digitalSignature",
 
 class X509_ExtKeyUsage(ASN1_Packet):
     ASN1_codec = ASN1_Codecs.BER
-    ASN1_root = ASN1F_FLAGS("keyUsage", "101", ku_mapping)
+    ASN1_root = ASN1F_FLAGS("keyUsage", "101", _ku_mapping)
     def get_keyUsage(self):
         return self.ASN1_root.get_flags(self)
 
@@ -380,7 +381,7 @@ class X509_ExtCRLNumber(ASN1_Packet):
     ASN1_codec = ASN1_Codecs.BER
     ASN1_root = ASN1F_INTEGER("cRLNumber", 0)
 
-cRL_reasons = ["unspecified",
+_cRL_reasons = ["unspecified",
                "keyCompromise",
                "cACompromise",
                "affiliationChanged",
@@ -394,7 +395,7 @@ cRL_reasons = ["unspecified",
 
 class X509_ExtReasonCode(ASN1_Packet):
     ASN1_codec = ASN1_Codecs.BER
-    ASN1_root = ASN1F_ENUMERATED("cRLReason", 0, cRL_reasons)
+    ASN1_root = ASN1F_ENUMERATED("cRLReason", 0, _cRL_reasons)
 
 class X509_ExtDeltaCRLIndicator(ASN1_Packet):
     ASN1_codec = ASN1_Codecs.BER
@@ -414,7 +415,7 @@ class X509_ExtIssuingDistributionPoint(ASN1_Packet):
                                   implicit_tag=0x82),
                     ASN1F_optional(
                         ASN1F_FLAGS("onlySomeReasons", None,
-                                    reasons_mapping,
+                                    _reasons_mapping,
                                     implicit_tag=0x83)),
                     ASN1F_BOOLEAN("indirectCRL", False,
                                   implicit_tag=0x84),
@@ -438,7 +439,7 @@ class X509_ExtIssuerAltName(ASN1_Packet):
     ASN1_root = ASN1F_SEQUENCE_OF("issuerAltName", [], X509_GeneralName)
 
 class X509_ExtGeneralSubtree(ASN1_Packet):
-# 'minimum' is not optional in RFC 5280, yet it is in some implementations.
+    # 'minimum' is not optional in RFC 5280, yet it is in some implementations.
     ASN1_codec = ASN1_Codecs.BER
     ASN1_root = ASN1F_SEQUENCE(
                     ASN1F_PACKET("base", X509_GeneralName(), X509_GeneralName),
@@ -583,7 +584,7 @@ class X509_ExtDefault(ASN1_Packet):
 
 # oid-info.com shows that some extensions share multiple OIDs.
 # Here we only reproduce those written in RFC5280.
-ext_mapping = {
+_ext_mapping = {
         "2.5.29.9"      : X509_ExtSubjectDirectoryAttributes,
         "2.5.29.14"     : X509_ExtSubjectKeyIdentifier,
         "2.5.29.15"     : X509_ExtKeyUsage,
@@ -614,7 +615,7 @@ ext_mapping = {
         }
 
 class ASN1F_EXT_SEQUENCE(ASN1F_SEQUENCE):
-# We use explicit_tag=0x04 with extnValue as STRING encapsulation.
+    # We use explicit_tag=0x04 with extnValue as STRING encapsulation.
     def __init__(self, **kargs):
         seq = [ASN1F_OID("extnID", "2.5.29.19"),
                ASN1F_optional(
@@ -637,8 +638,8 @@ class ASN1F_EXT_SEQUENCE(ASN1F_SEQUENCE):
             extnID.set_val(pkt, oid)
             s = critical.dissect(pkt, s)
             encapsed = X509_ExtDefault
-            if oid.val in ext_mapping:
-                encapsed = ext_mapping[oid.val]
+            if oid.val in _ext_mapping:
+                encapsed = _ext_mapping[oid.val]
             self.seq[2].cls = encapsed
             self.seq[2].cls.ASN1_root.flexible_tag = True
             # there are too many private extensions not to be flexible here
@@ -655,6 +656,13 @@ class X509_Extension(ASN1_Packet):
     ASN1_codec = ASN1_Codecs.BER
     ASN1_root = ASN1F_EXT_SEQUENCE()
 
+class X509_Extensions(ASN1_Packet):
+    # we use this in OCSP status requests, in tls/handshake.py
+    ASN1_codec = ASN1_Codecs.BER
+    ASN1_root = ASN1F_optional(
+                    ASN1F_SEQUENCE_OF("extensions",
+                                      None, X509_Extension))
+
 
 ####### Public key wrapper #######
 
@@ -748,10 +756,10 @@ class RSAPrivateKey_OpenSSL(ASN1_Packet):
                                      ECDSAPublicKey,
                                      explicit_tag=0xa1)))
 
-class _PacketFieldRaw(PacketField):
 # We need this hack because ECParameters parsing below must return
 # a Padding payload, and making the ASN1_Packet class have Padding
 # instead of Raw payload would break things...
+class _PacketFieldRaw(PacketField):
     def getfield(self, pkt, s):
         i = self.m2i(pkt, s)
         remain = ""
@@ -773,7 +781,7 @@ class ECDSAPrivateKey_OpenSSL(Packet):
 
 ####### TBSCertificate & Certificate #######
 
-default_issuer = [
+_default_issuer = [
         X509_RDN(),
         X509_RDN(
             rdn=[X509_AttributeTypeAndValue(
@@ -785,7 +793,7 @@ default_issuer = [
                  value=ASN1_PRINTABLE_STRING("Scapy Default Issuer"))])
             ]
 
-default_subject = [
+_default_subject = [
         X509_RDN(),
         X509_RDN(
             rdn=[X509_AttributeTypeAndValue(
@@ -807,7 +815,7 @@ class X509_Validity(ASN1_Packet):
                                   ASN1_UTC_TIME(str(ZuluTime(+86400))),
                                   ASN1F_UTC_TIME, ASN1F_GENERALIZED_TIME))
 
-attrName_mapping = [
+_attrName_mapping = [
         ("countryName"               , "C"),
         ("stateOrProvinceName"       , "ST"),
         ("localityName"              , "L"),
@@ -815,7 +823,7 @@ attrName_mapping = [
         ("organizationUnitName"      , "OU"),
         ("commonName"                , "CN")
         ]
-attrName_specials = [name for name, symbol in attrName_mapping]
+_attrName_specials = [name for name, symbol in _attrName_mapping]
 
 class X509_TBSCertificate(ASN1_Packet):
     ASN1_codec = ASN1_Codecs.BER
@@ -827,11 +835,11 @@ class X509_TBSCertificate(ASN1_Packet):
                     ASN1F_PACKET("signature",
                                  X509_AlgorithmIdentifier(),
                                  X509_AlgorithmIdentifier),
-                    ASN1F_SEQUENCE_OF("issuer", default_issuer, X509_RDN),
+                    ASN1F_SEQUENCE_OF("issuer", _default_issuer, X509_RDN),
                     ASN1F_PACKET("validity",
                                  X509_Validity(),
                                  X509_Validity),
-                    ASN1F_SEQUENCE_OF("subject", default_subject, X509_RDN),
+                    ASN1F_SEQUENCE_OF("subject", _default_subject, X509_RDN),
                     ASN1F_PACKET("subjectPublicKeyInfo",
                                  X509_SubjectPublicKeyInfo(),
                                  X509_SubjectPublicKeyInfo),
@@ -860,12 +868,12 @@ class X509_TBSCertificate(ASN1_Packet):
         """
         name_str = ""
         attrsDict = self.get_issuer()
-        for attrType, attrSymbol in attrName_mapping:
+        for attrType, attrSymbol in _attrName_mapping:
             if attrType in attrsDict:
                 name_str += "/" + attrSymbol + "="
                 name_str += attrsDict[attrType]
         for attrType in sorted(attrsDict):
-            if attrType not in attrName_specials:
+            if attrType not in _attrName_specials:
                 name_str += "/" + attrType + "="
                 name_str += attrsDict[attrType]
         return name_str
@@ -879,12 +887,12 @@ class X509_TBSCertificate(ASN1_Packet):
     def get_subject_str(self):
         name_str = ""
         attrsDict = self.get_subject()
-        for attrType, attrSymbol in attrName_mapping:
+        for attrType, attrSymbol in _attrName_mapping:
             if attrType in attrsDict:
                 name_str += "/" + attrSymbol + "="
                 name_str += attrsDict[attrType]
         for attrType in sorted(attrsDict):
-            if attrType not in attrName_specials:
+            if attrType not in _attrName_specials:
                 name_str += "/" + attrType + "="
                 name_str += attrsDict[attrType]
         return name_str
@@ -962,7 +970,7 @@ class X509_TBSCertList(ASN1_Packet):
                     ASN1F_PACKET("signature",
                                  X509_AlgorithmIdentifier(),
                                  X509_AlgorithmIdentifier),
-                    ASN1F_SEQUENCE_OF("issuer", default_issuer, X509_RDN),
+                    ASN1F_SEQUENCE_OF("issuer", _default_issuer, X509_RDN),
                     ASN1F_UTC_TIME("this_update", str(ZuluTime(-1))),
                     ASN1F_optional(
                         ASN1F_UTC_TIME("next_update", None)),
@@ -987,12 +995,12 @@ class X509_TBSCertList(ASN1_Packet):
         """
         name_str = ""
         attrsDict = self.get_issuer()
-        for attrType, attrSymbol in attrName_mapping:
+        for attrType, attrSymbol in _attrName_mapping:
             if attrType in attrsDict:
                 name_str += "/" + attrSymbol + "="
                 name_str += attrsDict[attrType]
         for attrType in sorted(attrsDict):
-            if attrType not in attrName_specials:
+            if attrType not in _attrName_specials:
                 name_str += "/" + attrType + "="
                 name_str += attrsDict[attrType]
         return name_str
@@ -1050,3 +1058,172 @@ class X509_CRL(ASN1_Packet):
     ASN1_codec = ASN1_Codecs.BER
     ASN1_root = ASN1F_X509_CRL()
 
+
+#############################
+#### OCSP Status packets ####
+#############################
+########### based on RFC 6960
+
+class OCSP_CertID(ASN1_Packet):
+    ASN1_codec = ASN1_Codecs.BER
+    ASN1_root = ASN1F_SEQUENCE(
+                    ASN1F_PACKET("hashAlgorithm",
+                                 X509_AlgorithmIdentifier(),
+                                 X509_AlgorithmIdentifier),
+                    ASN1F_STRING("issuerNameHash", ""),
+                    ASN1F_STRING("issuerKeyHash", ""),
+                    ASN1F_INTEGER("serialNumber", 0))
+
+class OCSP_GoodInfo(ASN1_Packet):
+    ASN1_codec = ASN1_Codecs.BER
+    ASN1_root = ASN1F_NULL("info", 0)
+
+class OCSP_RevokedInfo(ASN1_Packet):
+    ASN1_codec = ASN1_Codecs.BER
+    ASN1_root = ASN1F_SEQUENCE(
+                    ASN1F_GENERALIZED_TIME("revocationTime", ""),
+                    ASN1F_optional(
+                        ASN1F_PACKET("revocationReason", None,
+                                     X509_ExtReasonCode,
+                                     explicit_tag=0x80)))
+
+class OCSP_UnknownInfo(ASN1_Packet):
+    ASN1_codec = ASN1_Codecs.BER
+    ASN1_root = ASN1F_NULL("info", 0)
+
+class OCSP_CertStatus(ASN1_Packet):
+    ASN1_codec = ASN1_Codecs.BER
+    ASN1_root = ASN1F_CHOICE("certStatus", None,
+                    ASN1F_PACKET("good", OCSP_GoodInfo(),
+                                 OCSP_GoodInfo, implicit_tag=0x80),
+                    ASN1F_PACKET("revoked", OCSP_RevokedInfo(),
+                                 OCSP_RevokedInfo, implicit_tag=0xa1),
+                    ASN1F_PACKET("unknown", OCSP_UnknownInfo(),
+                                 OCSP_UnknownInfo, implicit_tag=0x82))
+
+class OCSP_SingleResponse(ASN1_Packet):
+    ASN1_codec = ASN1_Codecs.BER
+    ASN1_root = ASN1F_SEQUENCE(
+                    ASN1F_PACKET("certID", OCSP_CertID(), OCSP_CertID),
+                    ASN1F_PACKET("certStatus", OCSP_CertStatus(),
+                                 OCSP_CertStatus),
+                    ASN1F_GENERALIZED_TIME("thisUpdate", ""),
+                    ASN1F_optional(
+                        ASN1F_GENERALIZED_TIME("nextUpdate", "",
+                                               explicit_tag=0xa0)),
+                    ASN1F_optional(
+                        ASN1F_SEQUENCE_OF("singleExtensions", None,
+                                          X509_Extension,
+                                          explicit_tag=0xa1)))
+
+class OCSP_ByName(ASN1_Packet):
+    ASN1_codec = ASN1_Codecs.BER
+    ASN1_root = ASN1F_SEQUENCE_OF("byName", [], X509_RDN)
+
+class OCSP_ByKey(ASN1_Packet):
+    ASN1_codec = ASN1_Codecs.BER
+    ASN1_root = ASN1F_STRING("byKey", "")
+
+class OCSP_ResponderID(ASN1_Packet):
+    ASN1_codec = ASN1_Codecs.BER
+    ASN1_root = ASN1F_CHOICE("responderID", None,
+                    ASN1F_PACKET("byName", OCSP_ByName(), OCSP_ByName,
+                                 explicit_tag=0xa1),
+                    ASN1F_PACKET("byKey", OCSP_ByKey(), OCSP_ByKey,
+                                 explicit_tag=0xa2))
+
+class OCSP_ResponseData(ASN1_Packet):
+    ASN1_codec = ASN1_Codecs.BER
+    ASN1_root = ASN1F_SEQUENCE(
+                    ASN1F_optional(
+                        ASN1F_enum_INTEGER("version", 0, {0: "v1"},
+                                           explicit_tag=0x80)),
+                    ASN1F_PACKET("responderID", OCSP_ResponderID(),
+                                 OCSP_ResponderID),
+                    ASN1F_GENERALIZED_TIME("producedAt",
+                                           str(GeneralizedTime())),
+                    ASN1F_SEQUENCE_OF("responses", [], OCSP_SingleResponse),
+                    ASN1F_optional(
+                        ASN1F_SEQUENCE_OF("responseExtensions", None,
+                                          X509_Extension,
+                                          explicit_tag=0xa1)))
+
+class ASN1F_OCSP_BasicResponseECDSA(ASN1F_SEQUENCE):
+    def __init__(self, **kargs):
+        seq = [ASN1F_PACKET("tbsResponseData",
+                            OCSP_ResponseData(),
+                            OCSP_ResponseData),
+               ASN1F_PACKET("signatureAlgorithm",
+                            X509_AlgorithmIdentifier(),
+                            X509_AlgorithmIdentifier),
+               ASN1F_BIT_STRING_ENCAPS("signature",
+                            ECDSASignature(),
+                            ECDSASignature),
+               ASN1F_optional(
+                   ASN1F_SEQUENCE_OF("certs", None, X509_Cert,
+                                     explicit_tag=0xa0))]
+        ASN1F_SEQUENCE.__init__(self, *seq, **kargs)
+
+class ASN1F_OCSP_BasicResponse(ASN1F_SEQUENCE):
+    def __init__(self, **kargs):
+        seq = [ASN1F_PACKET("tbsResponseData",
+                            OCSP_ResponseData(),
+                            OCSP_ResponseData),
+               ASN1F_PACKET("signatureAlgorithm",
+                            X509_AlgorithmIdentifier(),
+                            X509_AlgorithmIdentifier),
+               ASN1F_BIT_STRING("signature",
+                                "defaultsignature"*2),
+               ASN1F_optional(
+                   ASN1F_SEQUENCE_OF("certs", None, X509_Cert,
+                                     explicit_tag=0xa0))]
+        ASN1F_SEQUENCE.__init__(self, *seq, **kargs)
+    def m2i(self, pkt, x):
+        c,s = ASN1F_SEQUENCE.m2i(self, pkt, x)
+        sigtype = pkt.fields["signatureAlgorithm"].algorithm.oidname
+        if "rsa" in sigtype.lower():
+            return c,s
+        elif "ecdsa" in sigtype.lower():
+            return ASN1F_OCSP_BasicResponseECDSA().m2i(pkt, x)
+        else:
+            raise Exception("could not parse OCSP basic response")
+    def dissect(self, pkt, s):
+        c,x = self.m2i(pkt, s)
+        return x
+    def build(self, pkt):
+        if "signatureAlgorithm" in pkt.fields:
+            sigtype = pkt.fields['signatureAlgorithm'].algorithm.oidname
+        else:
+            sigtype = pkt.default_fields["signatureAlgorithm"].algorithm.oidname
+        if "rsa" in sigtype.lower():
+            return ASN1F_SEQUENCE.build(self, pkt)
+        elif "ecdsa" in sigtype.lower():
+            pkt.default_fields["signatureValue"] = ECDSASignature()
+            return ASN1F_OCSP_BasicResponseECDSA().build(pkt)
+        else:
+            raise Exception("could not build OCSP basic response")
+
+class OCSP_ResponseBytes(ASN1_Packet):
+    ASN1_codec = ASN1_Codecs.BER
+    ASN1_root = ASN1F_SEQUENCE(
+                    ASN1F_OID("responseType", "1.3.6.1.5.5.7.48.1.1"),
+                    ASN1F_OCSP_BasicResponse(explicit_tag=0x04))
+
+_responseStatus_mapping = ["successful",
+                          "malformedRequest",
+                          "internalError",
+                          "tryLater",
+                          "notUsed",
+                          "sigRequired",
+                          "unauthorized"]
+
+class OCSP_Response(ASN1_Packet):
+    ASN1_codec = ASN1_Codecs.BER
+    ASN1_root = ASN1F_SEQUENCE(
+                    ASN1F_ENUMERATED("responseStatus", 0,
+                                     _responseStatus_mapping),
+                    ASN1F_optional(
+                        ASN1F_PACKET("responseBytes", None,
+                                     OCSP_ResponseBytes,
+                                     explicit_tag=0xa0)))
+
diff --git a/scapy/utils.py b/scapy/utils.py
index 34c78dd463f8c9d78e8d61e4134ab4ac5b16a484..9d2a56c0a347702edfc56931f6f954022635a9b7 100644
--- a/scapy/utils.py
+++ b/scapy/utils.py
@@ -152,6 +152,10 @@ def hexstr(x, onlyasc=0, onlyhex=0):
         s.append(sane(x)) 
     return "  ".join(s)
 
+def repr_hex(s):
+    """ Convert provided bitstring to a simple string of hex digits """
+    return "".join(map(lambda x: "%02x" % ord(x),s))
+
 @conf.commands.register
 def hexdiff(x,y):
     """Show differences between 2 binary strings"""
@@ -343,8 +347,34 @@ def mac2str(mac):
 def str2mac(s):
     return ("%02x:"*6)[:-1] % tuple(map(ord, s)) 
 
-def strxor(x,y):
-    return "".join(map(lambda x,y:chr(ord(x)^ord(y)),x,y))
+def randstring(l):
+    """
+    Returns a random string of length l (l >= 0)
+    """
+    tmp = map(lambda x: struct.pack("B", random.randrange(0, 256, 1)), [""]*l)
+    return "".join(tmp)
+
+def zerofree_randstring(l):
+    """
+    Returns a random string of length l (l >= 0) without zero in it.
+    """
+    tmp = map(lambda x: struct.pack("B", random.randrange(1, 256, 1)), [""]*l)
+    return "".join(tmp)
+
+def strxor(s1, s2):
+    """
+    Returns the binary XOR of the 2 provided strings s1 and s2. s1 and s2
+    must be of same length.
+    """
+    return "".join(map(lambda x,y:chr(ord(x)^ord(y)), s1, s2))
+
+def strand(s1, s2):
+    """
+    Returns the binary AND of the 2 provided strings s1 and s2. s1 and s2
+    must be of same length.
+    """
+    return "".join(map(lambda x,y:chr(ord(x)&ord(y)), s1, s2))
+
 
 # Workaround bug 643005 : https://sourceforge.net/tracker/?func=detail&atid=105470&aid=643005&group_id=5470
 try:
diff --git a/test/cert.uts b/test/cert.uts
index 876286d26b414b9c59bb317fb0c2ac67a3b6e21e..c43652cd7ae12251078acb7f0264584189f8df7c 100644
--- a/test/cert.uts
+++ b/test/cert.uts
@@ -32,6 +32,7 @@ TL1SGhzwfinME1e6p3Hm//pDjuJvFaY22k05LgLuyqc59vFiB3Toldz8+AbMNjvz
 AwIDAQAB
 -----END PUBLIC KEY-----
 """)
+x_pubNum = x.pubkey.public_numbers()
 type(x) is PubKeyRSA
 
 = PubKey class : key format is PEM
@@ -39,16 +40,17 @@ x.frmt == "PEM"
 
 = PubKey class : Importing DER-encoded RSA Key
 y = PubKey('0\x82\x01"0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x000\x82\x01\n\x02\x82\x01\x01\x00\x98Wj?\xe9\xd3\x11\x9b\xa4KIK?\xec\xa3\xd6\x03H\x9a\xc1\x08\x7f\xb3\xf6\xc9$\xee\x9d\xc7\x98\xc7\t&\xe1Q9A\x17\x83m\xbd\x8b\xe7\xf1\xcb\x03\xdaO\x98\x87\x90-*\xbf\x06\x03\xb5\x99\xe3\x9cl\xe4\x89\xd9\x85GCo\x0cC\x9e\xbe\xf0*\xdb\xea}\xbc\x8b\'\x17\xe2\x1at\x1fp1D\x08\xe1\xd1\xe7W\xfa\xad\xf2\x8a[\xd8\'\x85\xbd\xfc\xd9\xc8o\xfc\x00g\x04\xb4\xa0\x98\x9f\xfe\xd4\xe4T^\xfb\x1f&\xc0|\x97^\xe4J\x9b\xa7\xe6\xc2(\x8b\xccZv\xa6n\x1fCEL\xa3\xac\x10Y\xa3\x97@\xd6\x8d\xf6\xce\x9b\x85\x06\xb2]#\xc7fR\x9c=\x82\xd7\xf4\x17@Z\xf2Q\x99\x9b\xc5*sA\xb2]\xe5\xce%A6\xbb\xb0\xa22\xed\xcc\xef\xb0L\xe9\x92\xcbM\xca0\xe7\xe6\xd0"i&L\xbdR\x1a\x1c\xf0~)\xcc\x13W\xba\xa7q\xe6\xff\xfaC\x8e\xe2o\x15\xa66\xdaM9.\x02\xee\xca\xa79\xf6\xf1b\x07t\xe8\x95\xdc\xfc\xf8\x06\xcc6;\xf3\x03\x02\x03\x01\x00\x01')
+y_pubNum = y.pubkey.public_numbers()
 type(y) is PubKeyRSA
 
 = PubKey class : key format is DER
 y.frmt == "DER"
 
 = PubKey class : checking modulus value
-x.modulus == y.modulus and x.modulus == 19231328316532061413420367242571475005688288081144416166988378525696075445024135424022026378563116068168327239354659928492979285632474448448624869172454076124150405352043642781483254546569202103296262513098482624188672299255268092629150366527784294463900039290024710152521604731213565912934889752122898104556895316819303096201441834849255370122572613047779766933573375974464479123135292080801384304131606933504677232323037116557327478512106367095125103346134248056463878553619525193565824925835325216545121044922690971718737998420984924512388011040969150550056783451476150234324593710633552558175109683813482739004163L
+x_pubNum.n == y_pubNum.n and x_pubNum.n == 19231328316532061413420367242571475005688288081144416166988378525696075445024135424022026378563116068168327239354659928492979285632474448448624869172454076124150405352043642781483254546569202103296262513098482624188672299255268092629150366527784294463900039290024710152521604731213565912934889752122898104556895316819303096201441834849255370122572613047779766933573375974464479123135292080801384304131606933504677232323037116557327478512106367095125103346134248056463878553619525193565824925835325216545121044922690971718737998420984924512388011040969150550056783451476150234324593710633552558175109683813482739004163L
 
 = PubKey class : checking public exponent value
-x.pubExp == y.pubExp and x.pubExp == 65537L
+x_pubNum.e == y_pubNum.e and x_pubNum.e == 65537L
 
 = PubKey class : Importing PEM-encoded ECDSA public key
 z = PubKey("""
@@ -60,10 +62,10 @@ Jd5qtmDF2Zu+xrwrBRT0HBnPweDU+RsFxcyU/QxD9WYORzYarqxbcA==
 type(z) is PubKeyECDSA
 
 = PubKey class : checking curve
-z.key.curve.name == "SECP256k1"
+z.pubkey.curve.name == "secp256k1"
 
 = PubKey class : checking point value
-z.key.pubkey.point.x() == 104748656174769496952370005421566518252704263000192720134585149244759951661467L
+z.pubkey.public_numbers().x == 104748656174769496952370005421566518252704263000192720134585149244759951661467L
 
 
 ########### PrivKey class ###############################################
@@ -100,18 +102,20 @@ i5+Mqk9ZCGdoReVbAovJFoRqe7Fj9yWM+b1awGjL0bOTtnqx0iljob6uFyhpl1xg
 W3a3ICJ/ZYLvkgb4IBEteOwWpp37fX57vzhW8EmUV2UX7ve1uNRI
 -----END RSA PRIVATE KEY-----
 """)
+x_privNum = x.key.private_numbers()
+x_pubNum = x.pubkey.public_numbers()
 type(x) is PrivKeyRSA
 
 = PrivKey class : checking public attributes
-assert(x.modulus == 19231328316532061413420367242571475005688288081144416166988378525696075445024135424022026378563116068168327239354659928492979285632474448448624869172454076124150405352043642781483254546569202103296262513098482624188672299255268092629150366527784294463900039290024710152521604731213565912934889752122898104556895316819303096201441834849255370122572613047779766933573375974464479123135292080801384304131606933504677232323037116557327478512106367095125103346134248056463878553619525193565824925835325216545121044922690971718737998420984924512388011040969150550056783451476150234324593710633552558175109683813482739004163L)
-x.pubExp == 65537L
+assert(x_pubNum.n == 19231328316532061413420367242571475005688288081144416166988378525696075445024135424022026378563116068168327239354659928492979285632474448448624869172454076124150405352043642781483254546569202103296262513098482624188672299255268092629150366527784294463900039290024710152521604731213565912934889752122898104556895316819303096201441834849255370122572613047779766933573375974464479123135292080801384304131606933504677232323037116557327478512106367095125103346134248056463878553619525193565824925835325216545121044922690971718737998420984924512388011040969150550056783451476150234324593710633552558175109683813482739004163L)
+x_pubNum.e == 65537L
 
 = PrivKey class : checking private attributes
-assert(x.prime1 == 140977881300857803928857666115326329496639762170623218602431133528876162476487960230341078724702018316260690172014674492782486113504117653531825010840338251572887403113276393351318549036549656895326851872473595350667293402676143426484331639796163189182788306480699144107905869179435145810212051656274284113969L)
-assert(x.prime2 == 136413798668820291889092636919077529673097927884427227010121877374504825870002258140616512268521246045642663981036167305976907058413796938050224182519965099316625879807962173794483933183111515251808827349718943344770056106787713032506379905031673992574818291891535689493330517205396872699985860522390496583027L)
-assert(x.exponent1 == 46171616708754015342920807261537213121074749458020000367465429453038710215532257783908950878847126373502288079285334594398328912526548076894076506899568491565992572446455658740752572386903609191774044411412991906964352741123956581870694330173563737928488765282233340389888026245745090096745219902501964298369L)
-assert(x.exponent2 == 58077388505079936284685944662039782610415160654764308528562806086690474868010482729442634318267235411531220690585030443434512729356878742778542733733189895801341155353491318998637269079682889033003797865508917973141494201620317820971253064836562060222814287812344611566640341960495346782352037479526674026269L)
-x.privExp == 15879630313397508329451198152673380989865598204237760057319927734227125481903063742175442230739018051313441697936698689753842471306305671266572085925009572141819112648211571007521954312641597446020984266846581125287547514750428503480880603089110687015181510081018160579576523796170439894692640171752302225125980423560965987469457505107324833137678663960560798216976668670722016960863268272661588745006387723814962668678285659376534048525020951633874488845649968990679414325096323920666486328886913648207836459784281744709948801682209478580185160477801656666089536527545026197569990716720623647770979759861119273292833L
+assert(x_privNum.p == 140977881300857803928857666115326329496639762170623218602431133528876162476487960230341078724702018316260690172014674492782486113504117653531825010840338251572887403113276393351318549036549656895326851872473595350667293402676143426484331639796163189182788306480699144107905869179435145810212051656274284113969L)
+assert(x_privNum.q == 136413798668820291889092636919077529673097927884427227010121877374504825870002258140616512268521246045642663981036167305976907058413796938050224182519965099316625879807962173794483933183111515251808827349718943344770056106787713032506379905031673992574818291891535689493330517205396872699985860522390496583027L)
+assert(x_privNum.dmp1 == 46171616708754015342920807261537213121074749458020000367465429453038710215532257783908950878847126373502288079285334594398328912526548076894076506899568491565992572446455658740752572386903609191774044411412991906964352741123956581870694330173563737928488765282233340389888026245745090096745219902501964298369L)
+assert(x_privNum.dmq1 == 58077388505079936284685944662039782610415160654764308528562806086690474868010482729442634318267235411531220690585030443434512729356878742778542733733189895801341155353491318998637269079682889033003797865508917973141494201620317820971253064836562060222814287812344611566640341960495346782352037479526674026269L)
+x_privNum.d == 15879630313397508329451198152673380989865598204237760057319927734227125481903063742175442230739018051313441697936698689753842471306305671266572085925009572141819112648211571007521954312641597446020984266846581125287547514750428503480880603089110687015181510081018160579576523796170439894692640171752302225125980423560965987469457505107324833137678663960560798216976668670722016960863268272661588745006387723814962668678285659376534048525020951633874488845649968990679414325096323920666486328886913648207836459784281744709948801682209478580185160477801656666089536527545026197569990716720623647770979759861119273292833L
 
 = PrivKey class : Importing PEM-encoded ECDSA private key
 y = PrivKey("""
@@ -124,11 +128,24 @@ weDU+RsFxcyU/QxD9WYORzYarqxbcA==
 type(y) is PrivKeyECDSA
 
 = PrivKey class : checking public attributes
-assert(y.key.curve.name == "SECP256k1")
-y.key.privkey.public_key.point.y() == 86290575637772818452062569410092503179882738810918951913926481113065456425840L
+assert(y.key.curve.name == "secp256k1")
+y.key.public_key().public_numbers().y == 86290575637772818452062569410092503179882738810918951913926481113065456425840L
 
 = PrivKey class : checking private attributes
-y.key.privkey.secret_multiplier == 90719786431263082134670936670180839782031078050773732489701961692235185651857L
+y.key.private_numbers().private_value == 90719786431263082134670936670180839782031078050773732489701961692235185651857L
+
+
+########### PKCS crypto #############################################
+# these are legacy tests which should be removed eventually (see our pkcs1.py)
+
++ PKCS 1 legacy tests
+
+= PKCS 1 legacy : RSA signature & verification
+m = "Testing our PKCS #1 legacy methods"
+s = x.sign_legacy(m, t="pkcs", h="tls")
+assert(s == "\x0cm\x8a\x8f\xae`o\xcdC=\xfea\xf4\xff\xf0i\xfe\xa3!\xfd\xa5=*\x99?\x08!\x03A~\xa3-B\xe8\xca\xaf\xb4H|\xa3\x98\xe9\xd5U\xfdL\xb1\x9c\xd8\xb2{\xa1/\xfcr\x8c\xa7\xd3\xa9%\xde\x13\xa8\xf6\xc6<\xc7\xdb\xe3\xa62\xeb\xe9?\xe5by\xc2\x9e\xad\xec\x92:\x14\xd96\xa8\xc0+\xea8'{=\x91$\xdf\xed\xe1+eF8\x9fI\x1f\xa1\xcb4s\xd1#\xdf\xa11\x88o\x050i Hg\x0690\xe6\xe8?\\<:k\x94\x82\x91\x0f\x06\xc7>ZQ\xc2\xcdn\xdb\xf4\x9d\x7f!\xa9>\xe8\xea\xb3\xd83]\x8d\x90\xd4\xa0b\xe6\xe6$d[\xe4\xb4 |W\xb2t\x8c\xb2\xd5>>+\xf1\xa6W'\xaf\xc2CU\x82\x13\xc4\x0b\xc4vD*\xc3\xef\xa6s\nQ\xe6\rS@B\xd2\xa4V\xdc\xd1D\x7f\x00\xaa\xac\xac\x96i\xf1kg*\xe9*\x90a@\xc8uDy\x16\xe2\x03\xd1\x9fa\xe2s\xdb\xees\xa4\x8cna\xba\xdaE\x006&\xa4")
+x_pub = PubKey((x._pubExp, x._modulus, x._modulusLen))
+x_pub.verify_legacy(m, s, t="pkcs", h="tls")
 
 
 ########### Cert class ##############################################
@@ -194,8 +211,9 @@ x.notAfter == (2026, 3, 30, 7, 38, 59, 0, 89, -1)
 
 = Cert class : Checking RSA public key
 assert(type(x.pubKey) is PubKeyRSA)
-assert(x.pubKey.modulus == 19231328316532061413420367242571475005688288081144416166988378525696075445024135424022026378563116068168327239354659928492979285632474448448624869172454076124150405352043642781483254546569202103296262513098482624188672299255268092629150366527784294463900039290024710152521604731213565912934889752122898104556895316819303096201441834849255370122572613047779766933573375974464479123135292080801384304131606933504677232323037116557327478512106367095125103346134248056463878553619525193565824925835325216545121044922690971718737998420984924512388011040969150550056783451476150234324593710633552558175109683813482739004163L)
-x.pubKey.pubExp == 0x10001
+x_pubNum = x.pubKey.pubkey.public_numbers()
+assert(x_pubNum.n == 19231328316532061413420367242571475005688288081144416166988378525696075445024135424022026378563116068168327239354659928492979285632474448448624869172454076124150405352043642781483254546569202103296262513098482624188672299255268092629150366527784294463900039290024710152521604731213565912934889752122898104556895316819303096201441834849255370122572613047779766933573375974464479123135292080801384304131606933504677232323037116557327478512106367095125103346134248056463878553619525193565824925835325216545121044922690971718737998420984924512388011040969150550056783451476150234324593710633552558175109683813482739004163L)
+x_pubNum.e == 0x10001
 
 = Cert class : Checking extensions
 assert(x.cA)
@@ -223,8 +241,9 @@ JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv
 
 = Cert class : Checking ECDSA public key
 assert(type(y.pubKey) is PubKeyECDSA)
-assert(y.pubKey.key.curve.name == 'SECP384r1')
-y.pubKey.key.pubkey.point.x() == 3987178688175281746349180015490646948656137448666005327832107126183726641822596270780616285891030558662603987311874L
+pubkey = y.pubKey.pubkey
+assert(pubkey.curve.name == 'secp384r1')
+pubkey.public_numbers().x == 3987178688175281746349180015490646948656137448666005327832107126183726641822596270780616285891030558662603987311874L
 
 = Cert class : Checking ECDSA signature
 y.signatureValue == '0d\x020%\xa4\x81E\x02k\x12KutO\xc8#\xe3p\xf2ur\xde|\x89\xf0\xcf\x91ra\x9e^\x10\x92YV\xb9\x83\xc7\x10\xe78\xe9X&6}\xd5\xe44\x869\x020|6S\xf00\xe5bc:\x99\xe2\xb6\xa3;\x9b4\xfa\x1e\xda\x10\x92q^\x91\x13\xa7\xdd\xa4n\x92\xcc2\xd6\xf5!f\xc7/\xea\x96cjeE\x92\x95\x01\xb4'
diff --git a/test/tls.uts b/test/tls.uts
new file mode 100644
index 0000000000000000000000000000000000000000..e24d203df6da73108140bac85154cb37fcb5969b
--- /dev/null
+++ b/test/tls.uts
@@ -0,0 +1,957 @@
+% Tests for TLS module
+# 
+# Try me with :
+# bash test/run_tests -t test/tls.uts -F
+
+~ crypto
+
+###############################################################################
+################################### Crypto ####################################
+###############################################################################
+
+###############################################################################
+### HMAC                                                                    ###
+###############################################################################
+
++ Test Hmac_MD5
+= Crypto - Hmac_MD5 instantiation, parameter check 
+from scapy.layers.tls.crypto.h_mac import Hmac_MD5
+a = Hmac_MD5("somekey")
+a.key_len == 16 and a.hmac_len == 16
+
+= Crypto - Hmac_MD5 behavior on test vectors from RFC 2202 (+ errata)
+a = Hmac_MD5
+t1 = a('\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b').digest("Hi There") == '\x92\x94\x72\x7a\x36\x38\xbb\x1c\x13\xf4\x8e\xf8\x15\x8b\xfc\x9d'
+t2 = a('Jefe').digest('what do ya want for nothing?') == '\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38'
+t3 = a('\xaa'*16).digest('\xdd'*50) == '\x56\xbe\x34\x52\x1d\x14\x4c\x88\xdb\xb8\xc7\x33\xf0\xe8\xb3\xf6'
+t4 = a('\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19').digest('\xcd'*50) == '\x69\x7e\xaf\x0a\xca\x3a\x3a\xea\x3a\x75\x16\x47\x46\xff\xaa\x79'
+t5 = a('\x0c'*16).digest("Test With Truncation") == '\x56\x46\x1e\xf2\x34\x2e\xdc\x00\xf9\xba\xb9\x95\x69\x0e\xfd\x4c'
+t6 = a('\xaa'*80).digest("Test Using Larger Than Block-Size Key - Hash Key First") == '\x6b\x1a\xb7\xfe\x4b\xd7\xbf\x8f\x0b\x62\xe6\xce\x61\xb9\xd0\xcd'
+t7 = a('\xaa'*80).digest("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data") == '\x6f\x63\x0f\xad\x67\xcd\xa0\xee\x1f\xb1\xf5\x62\xdb\x3a\xa5\x3e'
+t1 and t2 and t3 and t4 and t5 and t6 and t7
+
+
++ Test Hmac_SHA
+= Crypto - Hmac_SHA instantiation, parameter check 
+from scapy.layers.tls.crypto.h_mac import Hmac_SHA
+a = Hmac_SHA("somekey")
+a.key_len == 20 and a.hmac_len == 20
+
+= Crypto - Hmac_SHA behavior on test vectors from RFC 2202 (+ errata)
+a = Hmac_SHA
+t1 = a('\x0b'*20).digest("Hi There") == '\xb6\x17\x31\x86\x55\x05\x72\x64\xe2\x8b\xc0\xb6\xfb\x37\x8c\x8e\xf1\x46\xbe\x00'
+t2 = a('Jefe').digest("what do ya want for nothing?") == '\xef\xfc\xdf\x6a\xe5\xeb\x2f\xa2\xd2\x74\x16\xd5\xf1\x84\xdf\x9c\x25\x9a\x7c\x79'
+t3 = a('\xaa'*20).digest('\xdd'*50) == '\x12\x5d\x73\x42\xb9\xac\x11\xcd\x91\xa3\x9a\xf4\x8a\xa1\x7b\x4f\x63\xf1\x75\xd3'
+t4 = a('\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19').digest('\xcd'*50) == '\x4c\x90\x07\xf4\x02\x62\x50\xc6\xbc\x84\x14\xf9\xbf\x50\xc8\x6c\x2d\x72\x35\xda'
+t5 = a('\x0c'*20).digest("Test With Truncation") == '\x4c\x1a\x03\x42\x4b\x55\xe0\x7f\xe7\xf2\x7b\xe1\xd5\x8b\xb9\x32\x4a\x9a\x5a\x04'
+t6 = a('\xaa'*80).digest("Test Using Larger Than Block-Size Key - Hash Key First") == '\xaa\x4a\xe5\xe1\x52\x72\xd0\x0e\x95\x70\x56\x37\xce\x8a\x3b\x55\xed\x40\x21\x12'
+t7 = a('\xaa'*80).digest("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data") == '\xe8\xe9\x9d\x0f\x45\x23\x7d\x78\x6d\x6b\xba\xa7\x96\x5c\x78\x08\xbb\xff\x1a\x91'
+t1 and t2 and t3 and t4 and t5 and t6 and t7
+
+
++ Test Hmac_SHA2
+= Crypto - Hmac_SHA2 behavior on test vectors from RFC 4231
+
+class _hmac_test_case_1:
+    Key          = ('\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b'+
+                    '\x0b\x0b\x0b\x0b\x0b\x0b\x0b')
+    Data         =  '\x48\x69\x20\x54\x68\x65\x72\x65'
+    HMAC_SHA_224 = ('\x89\x6f\xb1\x12\x8a\xbb\xdf\x19\x68\x32\x10\x7c\xd4'+
+                    '\x9d\xf3\x3f\x47\xb4\xb1\x16\x99\x12\xba\x4f\x53\x68'+
+                    '\x4b\x22')
+    HMAC_SHA_256 = ('\xb0\x34\x4c\x61\xd8\xdb\x38\x53\x5c\xa8\xaf\xce\xaf'+
+                    '\x0b\xf1\x2b\x88\x1d\xc2\x00\xc9\x83\x3d\xa7\x26\xe9'+
+                    '\x37\x6c\x2e\x32\xcf\xf7')
+    HMAC_SHA_384 = ('\xaf\xd0\x39\x44\xd8\x48\x95\x62\x6b\x08\x25\xf4\xab'+
+                    '\x46\x90\x7f\x15\xf9\xda\xdb\xe4\x10\x1e\xc6\x82\xaa'+
+                    '\x03\x4c\x7c\xeb\xc5\x9c\xfa\xea\x9e\xa9\x07\x6e\xde'+
+                    '\x7f\x4a\xf1\x52\xe8\xb2\xfa\x9c\xb6')
+    HMAC_SHA_512 = ('\x87\xaa\x7c\xde\xa5\xef\x61\x9d\x4f\xf0\xb4\x24\x1a'+
+                    '\x1d\x6c\xb0\x23\x79\xf4\xe2\xce\x4e\xc2\x78\x7a\xd0'+
+                    '\xb3\x05\x45\xe1\x7c\xde\xda\xa8\x33\xb7\xd6\xb8\xa7'+
+                    '\x02\x03\x8b\x27\x4e\xae\xa3\xf4\xe4\xbe\x9d\x91\x4e'+
+                    '\xeb\x61\xf1\x70\x2e\x69\x6c\x20\x3a\x12\x68\x54')
+
+class _hmac_test_case_2:
+    Key          = '\x4a\x65\x66\x65'
+    Data         = ('\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61\x20\x77\x61'+
+                    '\x6e\x74\x20\x66\x6f\x72\x20\x6e\x6f\x74\x68\x69\x6e'+
+                    '\x67\x3f')
+    HMAC_SHA_224 = ('\xa3\x0e\x01\x09\x8b\xc6\xdb\xbf\x45\x69\x0f\x3a\x7e'+
+                    '\x9e\x6d\x0f\x8b\xbe\xa2\xa3\x9e\x61\x48\x00\x8f\xd0'+
+                    '\x5e\x44')
+    HMAC_SHA_256 = ('\x5b\xdc\xc1\x46\xbf\x60\x75\x4e\x6a\x04\x24\x26\x08'+
+                    '\x95\x75\xc7\x5a\x00\x3f\x08\x9d\x27\x39\x83\x9d\xec'+
+                    '\x58\xb9\x64\xec\x38\x43')
+    HMAC_SHA_384 = ('\xaf\x45\xd2\xe3\x76\x48\x40\x31\x61\x7f\x78\xd2\xb5'+
+                    '\x8a\x6b\x1b\x9c\x7e\xf4\x64\xf5\xa0\x1b\x47\xe4\x2e'+
+                    '\xc3\x73\x63\x22\x44\x5e\x8e\x22\x40\xca\x5e\x69\xe2'+
+                    '\xc7\x8b\x32\x39\xec\xfa\xb2\x16\x49')
+    HMAC_SHA_512 = ('\x16\x4b\x7a\x7b\xfc\xf8\x19\xe2\xe3\x95\xfb\xe7\x3b'+
+                    '\x56\xe0\xa3\x87\xbd\x64\x22\x2e\x83\x1f\xd6\x10\x27'+
+                    '\x0c\xd7\xea\x25\x05\x54\x97\x58\xbf\x75\xc0\x5a\x99'+
+                    '\x4a\x6d\x03\x4f\x65\xf8\xf0\xe6\xfd\xca\xea\xb1\xa3'+
+                    '\x4d\x4a\x6b\x4b\x63\x6e\x07\x0a\x38\xbc\xe7\x37')
+
+class _hmac_test_case_3:
+    Key          = ('\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa')
+    Data         = ('\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd'+
+                    '\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd'+
+                    '\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd'+
+                    '\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd')
+    HMAC_SHA_224 = ('\x7f\xb3\xcb\x35\x88\xc6\xc1\xf6\xff\xa9\x69\x4d\x7d'+
+                    '\x6a\xd2\x64\x93\x65\xb0\xc1\xf6\x5d\x69\xd1\xec\x83'+
+                    '\x33\xea')
+    HMAC_SHA_256 = ('\x77\x3e\xa9\x1e\x36\x80\x0e\x46\x85\x4d\xb8\xeb\xd0'+
+                    '\x91\x81\xa7\x29\x59\x09\x8b\x3e\xf8\xc1\x22\xd9\x63'+
+                    '\x55\x14\xce\xd5\x65\xfe')
+    HMAC_SHA_384 = ('\x88\x06\x26\x08\xd3\xe6\xad\x8a\x0a\xa2\xac\xe0\x14'+
+                    '\xc8\xa8\x6f\x0a\xa6\x35\xd9\x47\xac\x9f\xeb\xe8\x3e'+
+                    '\xf4\xe5\x59\x66\x14\x4b\x2a\x5a\xb3\x9d\xc1\x38\x14'+
+                    '\xb9\x4e\x3a\xb6\xe1\x01\xa3\x4f\x27')
+    HMAC_SHA_512 = ('\xfa\x73\xb0\x08\x9d\x56\xa2\x84\xef\xb0\xf0\x75\x6c'+
+                    '\x89\x0b\xe9\xb1\xb5\xdb\xdd\x8e\xe8\x1a\x36\x55\xf8'+
+                    '\x3e\x33\xb2\x27\x9d\x39\xbf\x3e\x84\x82\x79\xa7\x22'+
+                    '\xc8\x06\xb4\x85\xa4\x7e\x67\xc8\x07\xb9\x46\xa3\x37'+
+                    '\xbe\xe8\x94\x26\x74\x27\x88\x59\xe1\x32\x92\xfb')
+
+class _hmac_test_case_4:
+    Key          = ('\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d'+
+                    '\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19')
+    Data         = ('\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd'+
+                    '\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd'+
+                    '\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd'+
+                    '\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd')
+    HMAC_SHA_224 = ('\x6c\x11\x50\x68\x74\x01\x3c\xac\x6a\x2a\xbc\x1b\xb3'+
+                    '\x82\x62\x7c\xec\x6a\x90\xd8\x6e\xfc\x01\x2d\xe7\xaf'+
+                    '\xec\x5a')
+    HMAC_SHA_256 = ('\x82\x55\x8a\x38\x9a\x44\x3c\x0e\xa4\xcc\x81\x98\x99'+
+                    '\xf2\x08\x3a\x85\xf0\xfa\xa3\xe5\x78\xf8\x07\x7a\x2e'+
+                    '\x3f\xf4\x67\x29\x66\x5b')
+    HMAC_SHA_384 = ('\x3e\x8a\x69\xb7\x78\x3c\x25\x85\x19\x33\xab\x62\x90'+
+                    '\xaf\x6c\xa7\x7a\x99\x81\x48\x08\x50\x00\x9c\xc5\x57'+
+                    '\x7c\x6e\x1f\x57\x3b\x4e\x68\x01\xdd\x23\xc4\xa7\xd6'+
+                    '\x79\xcc\xf8\xa3\x86\xc6\x74\xcf\xfb')
+    HMAC_SHA_512 = ('\xb0\xba\x46\x56\x37\x45\x8c\x69\x90\xe5\xa8\xc5\xf6'+
+                    '\x1d\x4a\xf7\xe5\x76\xd9\x7f\xf9\x4b\x87\x2d\xe7\x6f'+
+                    '\x80\x50\x36\x1e\xe3\xdb\xa9\x1c\xa5\xc1\x1a\xa2\x5e'+
+                    '\xb4\xd6\x79\x27\x5c\xc5\x78\x80\x63\xa5\xf1\x97\x41'+
+                    '\x12\x0c\x4f\x2d\xe2\xad\xeb\xeb\x10\xa2\x98\xdd')
+
+class _hmac_test_case_5:
+    Key          = ('\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c'+
+                    '\x0c\x0c\x0c\x0c\x0c\x0c\x0c')
+    Data         = ('\x54\x65\x73\x74\x20\x57\x69\x74\x68\x20\x54\x72\x75'+
+                    '\x6e\x63\x61\x74\x69\x6f\x6e')
+    HMAC_SHA_224 = ('\x0e*\xeah\xa9\x0c\x8d7\xc9\x88\xbc\xdb\x9f\xcao\xa8'+
+                    '\t\x9c\xd8W\xc7\xecJ\x18\x15\xca\xc5L')
+    HMAC_SHA_256 = ('\xa3\xb6\x16ts\x10\x0e\xe0n\x0cyl)UU+\xfao|\nj\x8a'+
+                    '\xef\x8b\x93\xf8`\xaa\xb0\xcd \xc5')
+    HMAC_SHA_384 = (':\xbf4\xc3P;*#\xa4n\xfca\x9b\xae\xf8\x97\xf4\xc8\xe4'+
+                    ',\x93L\xe5\\\xcb\xae\x97@\xfc\xbc\x1a\xf4\xcab&\x9e*'+
+                    '7\xcd\x88\xba\x92cA\xef\xe4\xae\xea')
+    HMAC_SHA_512 = ('A_\xadbqX\nS\x1dAy\xbc\x89\x1d\x87\xa6P\x18\x87\x07'+
+                    '\x92*O\xbb6f:\x1e\xb1m\xa0\x08q\x1c[P\xdd\xd0\xfc#P'+
+                    '\x84\xeb\x9d3d\xa1EO\xb2\xefg\xcd\x1d)\xfegs\x06\x8e'+
+                    '\xa2f\xe9k')
+
+class _hmac_test_case_6:
+    Key          = ('\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa')
+    Data         = ('\x54\x65\x73\x74\x20\x55\x73\x69\x6e\x67\x20\x4c\x61'+
+                    '\x72\x67\x65\x72\x20\x54\x68\x61\x6e\x20\x42\x6c\x6f'+
+                    '\x63\x6b\x2d\x53\x69\x7a\x65\x20\x4b\x65\x79\x20\x2d'+
+                    '\x20\x48\x61\x73\x68\x20\x4b\x65\x79\x20\x46\x69\x72'+
+                    '\x73\x74')
+    HMAC_SHA_224 = ('\x95\xe9\xa0\xdb\x96\x20\x95\xad\xae\xbe\x9b\x2d\x6f'+
+                    '\x0d\xbc\xe2\xd4\x99\xf1\x12\xf2\xd2\xb7\x27\x3f\xa6'+
+                    '\x87\x0e')
+    HMAC_SHA_256 = ('\x60\xe4\x31\x59\x1e\xe0\xb6\x7f\x0d\x8a\x26\xaa\xcb'+
+                    '\xf5\xb7\x7f\x8e\x0b\xc6\x21\x37\x28\xc5\x14\x05\x46'+
+                    '\x04\x0f\x0e\xe3\x7f\x54')
+    HMAC_SHA_384 = ('\x4e\xce\x08\x44\x85\x81\x3e\x90\x88\xd2\xc6\x3a\x04'+
+                    '\x1b\xc5\xb4\x4f\x9e\xf1\x01\x2a\x2b\x58\x8f\x3c\xd1'+
+                    '\x1f\x05\x03\x3a\xc4\xc6\x0c\x2e\xf6\xab\x40\x30\xfe'+
+                    '\x82\x96\x24\x8d\xf1\x63\xf4\x49\x52')
+    HMAC_SHA_512 = ('\x80\xb2\x42\x63\xc7\xc1\xa3\xeb\xb7\x14\x93\xc1\xdd'+
+                    '\x7b\xe8\xb4\x9b\x46\xd1\xf4\x1b\x4a\xee\xc1\x12\x1b'+
+                    '\x01\x37\x83\xf8\xf3\x52\x6b\x56\xd0\x37\xe0\x5f\x25'+
+                    '\x98\xbd\x0f\xd2\x21\x5d\x6a\x1e\x52\x95\xe6\x4f\x73'+
+                    '\xf6\x3f\x0a\xec\x8b\x91\x5a\x98\x5d\x78\x65\x98')
+
+class _hmac_test_case_7:
+    Key          = ('\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'+
+                    '\xaa')
+    Data         = ('\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73'+
+                    '\x74\x20\x75\x73\x69\x6e\x67\x20\x61\x20\x6c\x61\x72'+
+                    '\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63'+
+                    '\x6b\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20\x61\x6e'+
+                    '\x64\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68'+
+                    '\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65'+
+                    '\x20\x64\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b\x65'+
+                    '\x79\x20\x6e\x65\x65\x64\x73\x20\x74\x6f\x20\x62\x65'+
+                    '\x20\x68\x61\x73\x68\x65\x64\x20\x62\x65\x66\x6f\x72'+
+                    '\x65\x20\x62\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20'+
+                    '\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41\x43\x20\x61'+
+                    '\x6c\x67\x6f\x72\x69\x74\x68\x6d\x2e')
+    HMAC_SHA_224 = ('\x3a\x85\x41\x66\xac\x5d\x9f\x02\x3f\x54\xd5\x17\xd0'+
+                    '\xb3\x9d\xbd\x94\x67\x70\xdb\x9c\x2b\x95\xc9\xf6\xf5'+
+                    '\x65\xd1')
+    HMAC_SHA_256 = ('\x9b\x09\xff\xa7\x1b\x94\x2f\xcb\x27\x63\x5f\xbc\xd5'+
+                    '\xb0\xe9\x44\xbf\xdc\x63\x64\x4f\x07\x13\x93\x8a\x7f'+
+                    '\x51\x53\x5c\x3a\x35\xe2')
+    HMAC_SHA_384 = ('\x66\x17\x17\x8e\x94\x1f\x02\x0d\x35\x1e\x2f\x25\x4e'+
+                    '\x8f\xd3\x2c\x60\x24\x20\xfe\xb0\xb8\xfb\x9a\xdc\xce'+
+                    '\xbb\x82\x46\x1e\x99\xc5\xa6\x78\xcc\x31\xe7\x99\x17'+
+                    '\x6d\x38\x60\xe6\x11\x0c\x46\x52\x3e')
+    HMAC_SHA_512 = ('\xe3\x7b\x6a\x77\x5d\xc8\x7d\xba\xa4\xdf\xa9\xf9\x6e'+
+                    '\x5e\x3f\xfd\xde\xbd\x71\xf8\x86\x72\x89\x86\x5d\xf5'+
+                    '\xa3\x2d\x20\xcd\xc9\x44\xb6\x02\x2c\xac\x3c\x49\x82'+
+                    '\xb1\x0d\x5e\xeb\x55\xc3\xe4\xde\x15\x13\x46\x76\xfb'+
+                    '\x6d\xe0\x44\x60\x65\xc9\x74\x40\xfa\x8c\x6a\x58')
+
+def _all_hmac_sha2_tests():
+    from scapy.layers.tls.crypto.h_mac import (Hmac_SHA224, Hmac_SHA256,
+                                               Hmac_SHA384, Hmac_SHA512)
+    res = True
+    for t in [_hmac_test_case_1, _hmac_test_case_2, _hmac_test_case_3,
+              _hmac_test_case_4, _hmac_test_case_5, _hmac_test_case_6,
+              _hmac_test_case_7 ]:
+        tmp = ((Hmac_SHA224(t.Key).digest(t.Data) == t.HMAC_SHA_224) and
+               (Hmac_SHA256(t.Key).digest(t.Data) == t.HMAC_SHA_256) and
+               (Hmac_SHA384(t.Key).digest(t.Data) == t.HMAC_SHA_384) and
+               (Hmac_SHA512(t.Key).digest(t.Data) == t.HMAC_SHA_512))
+        res = res and tmp
+    return res
+
+_all_hmac_sha2_tests()
+
+
+###############################################################################
+### PRF                                                                     ###
+###############################################################################
+
++ Test _tls_P_MD5
+= Crypto - _tls_P_MD5 behavior on test vectors borrowed from RFC 2202 (+ errata)
+from scapy.layers.tls.crypto.prf import _tls_P_MD5
+t1 = _tls_P_MD5('\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b', "Hi There", 64) == '8\x99\xc0\xb8!\xd7}RI\xb2\xbb\x8e\xbe\xf8\x97Y\xcc\xffL\xae\xc3I\x8f\x7f .\x81\xe0\xce\x1a\x82\xbd\x19\xa0\x16\x10P}\xf0\xda\xdc\xa0>\xc4,\xa1\xcfS`\x85\xc5\x084+QN31b\xd7%L\x9d\xdc'
+t2 = _tls_P_MD5("Jefe", "what do ya want for nothing?", 64) == "\xec\x99'|,\xd5gj\x82\xb9\xa0\x12\xdb\x83\xd3\xa3\x93\x19\xa6N\x89g\x99\xc2!9\xd8\xcf\xc1WTi\xc4D \x19l\x03\xa8PCo\x10`-\x98\xd0\xe1\xbc\xefAJkx\x95\x0c\x08*\xd6C\x8fS\x0e\xd9"
+t3 = _tls_P_MD5('\xaa'*16,'\xdd'*50, 64) == '\xe5_\xe8.l\xee\xd8AP\xfc$$\xda\tX\x93O\xa7\xd2\xe2\xa2\xa9\x02\xa1\x07t\x19\xd1\xe3%\x80\x19\rV\x19\x0f\xfa\x01\xce\x0eJ\x7fN\xdf\xed\xb5lS\x06\xb5|\x96\xa6\x1cc)h\x88\x8d\x0c@\xfdX\xaa'
+t4 = _tls_P_MD5('\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19', '\xcd'*50, 64) == '\x8e\xa6\x1f\x82\x1e\xad\xbe4q\x93\xf4\x1c\xb7\x87\xb3\x15\x13F\x8b\xfd\x89m\x0e\xa6\xdc\xe9\xceZ\xcdOc>gN\xa4\x9cK\xf89\xfc6\t%T=j\xf0\x0f\xfdl\xbf\xfbj\xc4$zR"\xf4\xa4=\x18\x8b\x8d'
+t5 = _tls_P_MD5('\x0c'*16, "Test With Truncation", 64) == '\xb3>\xfaj\xc8\x95S\xcd\xdd\xea\x8b\xee7\xa5ru\xf4\x00\xd6\xed\xd5\x9aH\x1f,F\xb6\x93\r\xc3Z<"\x1e\xf7rx\xf0\xd7\x0f`zy\xe9\r\xb4\xf4}\xab2\xa5\xfe\xd0z@\x87\xc1c\x8b\xa0\xc8\xf5\x0bd'
+t6 = _tls_P_MD5('\xaa'*80, "Test Using Larger Than Block-Size Key - Hash Key First", 64) == ';\xcf\xa4\xd8\xccH\xa0\xa4\xf1\x10d\xfa\xd4\xb1\x7f\xda\x80\xf6\xe2\xb9\xf4\xd3WtS\x1c\x83\xb4(\x94\xfe\xa7\xb9\xc1\xcd\xf9\xe7\xae\xbc\x0c\x0f\xbae\xc3\x9e\x11\xe2+\x11\xe9\xd4\x8fK&\x99\xfe[\xfa\x02\x85\xb4\xd8\x8e\xdf'
+t7 = _tls_P_MD5('\xaa'*80, "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", 64) == '\x12\x06EI1\x81fP\x8dn\xa6WC\xfb\xbf\x1e\xefC[|\x0f\x05w\x14@\xfc\xa5 \xeak\xc9\xb9\x1c&\x80\x81.\x85#\xa9\x0ff\xea\xaa\x01"v\'\xd8X"\xbd\xa2\x86\xbd\xe3?6\xc7|\xc6WNO'
+t1 and t2 and t3 and t4 and t5 and t6 and t7
+
+
++ Test _tls_P_SHA1
+= Crypto - _tls_P_SHA1 behavior on test vectors borrowed from RFC 2202 (+ errata)
+from scapy.layers.tls.crypto.prf import _tls_P_SHA1
+t1 = _tls_P_SHA1('\x0b'*20, "Hi There", 80) == '\x13\r\x11Q7(\xc1\xad\x7f>%m\xfc\x08\xb6\xb9$\xb1MG\xe4\x9c\xcdY\x0e\\T\xd0\x8f\x1a-O@`\xd2\x9eV_\xfd\xed\x1f\x93V\xfb\x18\xb6\xbclq3A\xa2\x87\xb1u\xfc\xb3RQ\x19;#\n(\xd2o%lB\x8b\x01\x89\x1c6m"\xc3\xe2\xa0\xe7'
+t2 = _tls_P_SHA1('Jefe', "what do ya want for nothing?", 80) == '\xba\xc4i\xf1\xa0\xc5eO\x844\xb6\xbd%L\xe1\xfe\xef\x08\x00\x1c^l\xaf\xbbN\x9f\xd8\xe5}\x87U\xc1\xd2&4zu\x9a1\xef\xd6M+\x1e\x84\xb4\xcb\xc9\xa7\n\x90f\x8aJ\xde\xd5\xa4\x8f,D\xe8.\x98\x9c)\xc7hlct\x1em(\xb73b[L\x96c'
+t3 = _tls_P_SHA1('\xaa'*20, '\xdd'*50, 80) == 'Lm\x848}\xe8?\x88\x82\x85\xc3\xe6\xc9\x1f\x80Z\xf5D\xeeI\xa1m\x08h)\xea<zk{\x9b\x9b\xe1;H\xa4\xf5\x93r\x87\x07J0\n\xb9\xdd\\~j\xd0\x98R|C\x89\x131\x12u%\x90\xb2\x05\xb4}\xad}\xc4MP\x8cmb\x0c\x88\xfd{)\x9b\xc0'
+t4 = _tls_P_SHA1('\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19', '\xcd'*50, 80) == '\xd6\xe4\x8a\x91\xb3\xac\xe16\x9d\x10s\xf1\x1bu\x96(6f\xed\xd8x\x19\xcd<:\x15\xb2z\xc1\xa9\xdf\x89=\xeb!\xfb\n\x0e\xdf0\xb9\xb5\xa96\xcf\x9b\xd4\xcaD\x12Y1[p\xb9\xf9\xbb=\xa9\xcd\xb7\xe0L\xb00\xafK\xc4\x9c\xc6?#\xb6$\xebM\x1a\xba;3'
+t5 = _tls_P_SHA1('\x0c'*20, "Test With Truncation", 80) == '`\x1d\xe4\x98Q\xa1\xdbW\xc5a\xa9@\x8fQ\x86\xfc\x17\xca\xda\x1a\xdd\xb8\xab\x94M_Y\xd1%Pj\xfc\xd4\xca\x82\x88\xdb\x04\xf9F\xbe\xbf\xecR\xa4\x0c}[\x8e\xc7\xdf\x88I:\xea2v\xbe\x06\x8fcx\xf1Q\xb7z1\x1455?\xc0_\xda\xbb;\xa6Q\xb3\xc5'
+t6 = _tls_P_SHA1('\xaa'*80, "Test Using Larger Than Block-Size Key - Hash Key First", 80) == '\x00W\xbaq>^\x047;\xcezY}\x16\xc6\xf10\x80:\xe2K\x87i{\xc7V\xad2\xda=\xf3d7\x047\xf7r\xf1&\x04\xb1\xd1\xf8\x88H\'\r\x08\xc4\x81\xa3\xa1Q\xa5\x90\xed\xef\xd8\x9c\x14\xdc\x80\xab){3\xde\x87\x8a\x1e"\x1e\xad54rM\x94\xe1\xb8'
+t7 = _tls_P_SHA1('\xaa'*80, "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", 80) == 'N/PKC\x1d\xb5[}gUk\xc7\xaf\xb4-\xef\x9e\xe63$E=\xfc\xc4\xd0l]EA\x84\xb0\x1e\x91]\xcc[\x0e-\xec\xd5\x90\x19,\xc6\xffn\xf8\xbe1Ck\xe6\x9cF*\x8c"_\x05\x14%h\x98\xa1\xc2\xf1bCt\xd4S\xc1:{\x96\xa4\x14c '
+t1 and t2 and t3 and t4 and t5 and t6 and t7
+
+
++ Test _tls_PRF()
+= Crypto - _tls_PRF behavior on test vectors borrowed from RFC 2202 (+ errata)
+from scapy.layers.tls.crypto.prf import _tls_PRF
+t1 = _tls_PRF('\x0b'*20, "Test Label XXXX", "Hi There", 80) == 'E\xcc\xeb\x12\x0b<\xbfh\x1f\xc3\xd3%J\x85\xdeQ\t\xbc[\xcd.\xbe\x170\xf2\xebm\xe6g\x05x\xad\x86V\x0b\xb3\xb7\xe5i\x7fh}T\xe5$\xe4\xba\xa0\xc6\xf0\xf1\xb1\xe1\x8a\xf5\xcc\x9ab\x1c\xc9\x10\x82\x93\x82Q\xd2\x80\xf0\xf8\x0f\x03\xe2\xbe\xc3\x94T\x05\xben\x9e'
+t2 = _tls_PRF('Jefe', "Test Label YYYYYYY", "what do ya want for nothing?", 80) == 'n\xbet\x06\x82\x87\xcd\xea\xd9\x8b\xf8J\x17\x07\x84\xbc\xf3\x07\x9a\x99\n\xa6,\x97\xe6CRO\x7f\x0e[,\xa9\x83\xe6\xce?6\x12x\xc8Q\x00kO\x06s\xc5\xd7\xda\x1fd_\xe8\xad\xd4\xea\xfe\xd8\xc8 \x92e\x80\x8a\xafxF\xd6-/\x14\x94\x05a\x94\x0b\x1d\xf83'
+t3 = _tls_PRF('\xaa'*20, "Test Label ZZ", '\xdd'*50, 80) == "Ad\xe2B\xa0\xb0+G#\x0f%\x19\xae\xdd\xb1d\xa0\x99\x15\x98\xa43c?\xaa\xd1\xc0\xf7\xc39V\xcb\x9b}\x95T\xd9\xde \xecr{/\xfb\x018\xeeR \x18Awi\x86=\xb4rg\x13\\\xaf<\x17\xd3_\xc5'U[\xa5\x83\xfa<\xa6\xc9\xdd\x85l\x1a\xdb"
+t4 = _tls_PRF('\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19', "Test Label UUUUUUUUUUUUUUU", '\xcd'*50, 80) == '<\xf0\xe9\xaa\x95w\t\xa7\xb0!w\xf1EoC\x8fJ\x1f\xec\x80.\x89X\xe3O4Vl\xd1\xb7]\xa1\xb9o\xdf/&!\xb8n\xeb\x04"\xeftxs 6E+\xf1\xb3\xb6/vd\xd1h\xa3\x80>\x83Y\xbd]\xda\xab\xb8\xd8\x01\xc5b3K\xe7\x08\r\x12\x14'
+t5 = _tls_PRF('\x0c'*20, "Test Label KKKKKKKKK", "Test With Truncation", 80) == "gq\xa5\xc4\xf5\x86z.\x03\n\xa3\x85\x87\xbc\xabm\xf1\xd2\x06\xf6\xbc\xc8\xab\xf0\xee\xd2>e'!\xd3zW\x81\x10|^(\x8d~\xa5s&p\xef]\rDa\x113\xa6z\x9f\xf2\xe2_}\xd8.u\xbe\xb1\x7fx\xe0r~\xdc\xa2\x0f\xcd\xcd\x1d\x81\x1a`#\xc6O"
+t6 = _tls_PRF('\xaa'*80, "Test Label PPPPPPPPP", "Test Using Larger Than Block-Size Key - Hash Key First", 80) == '\x994^fx\x17\xbaaj\xc0"\xd1g\xbfh#uE\xee\xd8\xf1,\xab\xe7w\xfa\xc8\x0c\xf9\xcd\xbb\xbb\xa71U\xbe\xeb@\x90\xc2\x04\x93\xa5\xcf\x8e\xda\xbb\x93n\x99^\xa2{\x8b{\x18\xd7\xf7e\x8a~\xfbA\xdd\xc3\xd9\x9b\x1c\x82$\xf5YX{\xaa\xb4\xf2\x04\xb3%'
+t7 = _tls_PRF('\xaa'*80, "Test Label MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM", "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", 80) == '\xd6N\x12S\x18]\x87\x19\xacD\x1b4\xc3"\xc2\xd9J\xb8\xee/\xb0?\xc2_\x10\xb2\x196\xdaXC\xe0Ft\xd3:a\xcd\xb8\xdd\x8a\xb6\xb1\xc6sx\xb8\x87\x8a\x93\xf8~\xad\xc7\xd1\xa7I=\xceVW\x0f\x9a\xcc-\x8cv^o\x12\xa4\xcd\x10\xb1\xb0\x1f\xdd\x94,\x03'
+t1 and t2 and t3 and t4 and t5 and t6 and t7
+
+
++ Test _ssl_PRF()
+= Crypto - _ssl_PRF behavior on test vectors
+from scapy.layers.tls.crypto.prf import _ssl_PRF
+t1 = _ssl_PRF('\x0b'*20, "Hi There", 80) == '\x0fo\xbe9\x83>~Bc\xaea^\x86\xd2b\x94X\xfd9Be\xe799\xf2\x00\xfcS\xd6\x1c=\xe5\x7fin\x1e\xf9r\xc8\xe6k\x19K\x8a\x85SK\xe5\xb7;A\x19b\x86F3M\x8d=\xcf\x15\xeedo\xd3\xae\xa2\x95\x8e\x80\x13\xabG\x8d\x1c,\x8c\xab\xf7\xd4'
+t2 = _ssl_PRF('Jefe', "what do ya want for nothing?", 80) == '\x19\x9f\xb9{\x87.\xd0\xf5\xc4\t.\xb6#\xae\x95\xe0S~\x15\xce\xe6\xb7oe\xad\x127\xb8\xc2C?\r\x87\xa6\x7f\x86y\xfa\xae\xcf\x0e\xb9\x01\xa5B\x07\x9d\x95\xf1]\xdc\x1bCb&T\xa0\xb0\x8a3\xcf\\\xaf\xe8j/\xbdx\x13\\\x91\xc8\xdfZ\xde"R`K\xd6'
+t3 = _ssl_PRF('\xaa'*20, '\xdd'*50, 80) == '\xe3*\xce\xdc?k{\x10\x80\x8dt\x0e\xdaA\xf9}\x1d\x8e|\xc9Ux\x88\\\xf1a\xcfJ\xedi\xc1[C-\xf3\xa4\xcc\xf9\xce\xa3P\xe3\x9ai\x0b\xb7\xce\x8bar\x93\xc5\x93\x1a\x82\xc8{\x1c\xf2\x87\x9d\xe1\xf5\x9e\x0c\xf6\xa6\x91\xb9\x97\x17Y,\x11\x00\rs\xdd\xcf]'
+t4 = _ssl_PRF('\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19', '\xcd'*50, 80) == "\x8c\x83!h\x1b\xf2\x96f\x04\x15\x80H\x88\xcb\x80\x03\xc0\xfc\x05\xe5q\x93]\xeb\t\xd4B\xbc\xa4{\xb9\xd8\xb6IF\xc2\x80\x87\x9e2*\x82\x0ef\xc8\xbbBi\xb15\x90\xd6MW\xebM\xd7\xf9u\xd5+\xa8\x81\x11'\x8c\x88]b\r,\xde\xd9d[t\t\x199\x0b"
+t5 = _ssl_PRF('\x0c'*20, "Test With Truncation", 80) == "\x85\xf5\xe8\xd2\xddW$\x14\xde\x84\x08@\xca\x86\x8bZn\x07\x87AKg\x18\xc3\x1a'\xc2\xb9\xdd\x17\xb5K1\xb9\x9a=\xe4\x1f/\xfe\xa6\x96\x10\x0c\x15@:z\xbf\x1dM\xa3\x90\x01\xb67\x07Z\xe0\xfe}U=\x81\xb2~\xc6\x1a\xcb\xe7\x9b\x90+\xa0\x86\xb2\x8b\xae\xc7\x9f"
+t6 = _ssl_PRF('\xaa'*80, "Test Using Larger Than Block-Size Key - Hash Key First", 80) == '\x99\x11\x92\x8dw\xf1\xab\xdfr\x96S\xf5\xc1\x96\xc0\x16W*=\xa49\xd0\xf0\xf15\x91le\xda\x16\xfe8\x834kC3\x1b\xdf\xfc\xd8\x82\xe1\x9c\xfe9(4\xf9\x9c\x12\xc5~\xd1\xdc\xf3\xe5\x91\xbd\xbb\xb5$\x1c\xe4fs\xf2\xedM\xb7pO\x17\xdf\x01K\xf8\xed2-'
+t7 = _ssl_PRF('\xaa'*80, "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", 80) == "\x8esl|C\x81\x80vv\xe1\x89H\xc9'oC\x1b\xbe\xc3\xbbE\x04)\xed\x1c\x84\xa9)\x08\xf5\xeb-\x93\xe9\x0f}\xeb[\xc4w\xd53y$\x07\xdc\x0f\\\xfc\xb2\x05r+\x13\xd8\xc3\xe7Lsz\xa1\x03\x93\xdd-\xf9l\xb7\xe6\xb3\x7fM\xfa\x90\xadeo\xcer*"
+t1 and t2 and t3 and t4 and t5 and t6 and t7
+
+
++ Test PRF for TLS 1.2
+= Crypto - _tls12_*_PRF behavior, using SHA-256, SHA-384 and SHA-512
+# https://www.ietf.org/mail-archive/web/tls/current/msg03416.html
+
+from scapy.layers.tls.crypto.prf import PRF
+class _prf_tls12_sha256_test:
+    h= "SHA256"
+    k= "\x9b\xbe\x43\x6b\xa9\x40\xf0\x17\xb1\x76\x52\x84\x9a\x71\xdb\x35"
+    s= "\xa0\xba\x9f\x93\x6c\xda\x31\x18\x27\xa6\xf7\x96\xff\xd5\x19\x8c"
+    o=("\xe3\xf2\x29\xba\x72\x7b\xe1\x7b\x8d\x12\x26\x20\x55\x7c\xd4\x53" +
+       "\xc2\xaa\xb2\x1d\x07\xc3\xd4\x95\x32\x9b\x52\xd4\xe6\x1e\xdb\x5a")
+
+class _prf_tls12_sha384_test:
+    h= "SHA384"
+    k= "\xb8\x0b\x73\x3d\x6c\xee\xfc\xdc\x71\x56\x6e\xa4\x8e\x55\x67\xdf"
+    s= "\xcd\x66\x5c\xf6\xa8\x44\x7d\xd6\xff\x8b\x27\x55\x5e\xdb\x74\x65"
+    o=("\x7b\x0c\x18\xe9\xce\xd4\x10\xed\x18\x04\xf2\xcf\xa3\x4a\x33\x6a" +
+       "\x1c\x14\xdf\xfb\x49\x00\xbb\x5f\xd7\x94\x21\x07\xe8\x1c\x83\xcd")
+
+class _prf_tls12_sha512_test:
+    h= "SHA512"
+    k= "\xb0\x32\x35\x23\xc1\x85\x35\x99\x58\x4d\x88\x56\x8b\xbb\x05\xeb"
+    s= "\xd4\x64\x0e\x12\xe4\xbc\xdb\xfb\x43\x7f\x03\xe6\xae\x41\x8e\xe5"
+    o=("\x12\x61\xf5\x88\xc7\x98\xc5\xc2\x01\xff\x03\x6e\x7a\x9c\xb5\xed" +
+       "\xcd\x7f\xe3\xf9\x4c\x66\x9a\x12\x2a\x46\x38\xd7\xd5\x08\xb2\x83")
+
+def _all_prf_tls12_tests():
+    res = True
+    for t in [ _prf_tls12_sha256_test,
+               _prf_tls12_sha384_test,
+               _prf_tls12_sha512_test ]:
+        p = PRF(tls_version=0x303, hash_name=t.h)
+        tmp = p.prf(t.k, "test label", t.s, 32) == t.o
+        res = res and tmp
+    return res
+
+_all_prf_tls12_tests()
+
+
++ Test compute_master_secret() for SSL
+= Crypto - compute_master_secret() in SSL mode
+f = PRF(tls_version=0x300)
+t1 = f.compute_master_secret("A"*48, "B"*32, "C"*32) == '\xe8\xb5O68e\x8c\x1e\xd0hD!\xc1Zk\x9e\xc7x3\xfc".\xf9\x17\xd5B\xfc\xef\x8d\xed\x9fP\xcer\x83|6\x02\xe0\x86\xda\xab-G\x8c\xa9H5'
+t2 = f.compute_master_secret("A"*48, "C"*32, "B"*32) == 'Ts/q\x83\x88\x10\x9c1Y\xff\xf3vo\xe3\x8aM\x9b\xa3k[J\xeeWXs\xcfTe\x19\xc6\xb1\x0ebj1}\x0c\xca\x97=|\x88W\xd8q\xfb|'
+t3 = f.compute_master_secret("C"*48, "A"*32, "B"*32) == 'Q\xde\x06L\xdb\xe9\x9dC\x19\x8a:m@\xce\xbf\xc0\n\xd8\xd4H!#\x06\xad\x929\x85\xc9@\x1f\xb5\xe2)^{c\x94\x06&\xad\xb56\x13^\xd6\xa5\x19\xe7'
+t4 = f.compute_master_secret("D"*48, "B"*32, "A"*32) == '\xbe\x9a\xc8)\xb5{.H1\x8382\xc2\xdff\xdf@\xda\xde\x88\xe1\xf3\xad9\xcc\x14\xb1\x7f\x90\x00;B)\x8c\xdb\xdbH\xfe=%^\xe9\x83\x0eV\x86\x83\x8d'
+t1 and t2 and t3 and t4
+
+
++ Test derive_key_block() for SSL
+= Crypto - derive_key_block() in SSL mode
+t1 = f.derive_key_block("A"*48, "B"*32, "C"*32, 72) == '\xe8\xb5O68e\x8c\x1e\xd0hD!\xc1Zk\x9e\xc7x3\xfc".\xf9\x17\xd5B\xfc\xef\x8d\xed\x9fP\xcer\x83|6\x02\xe0\x86\xda\xab-G\x8c\xa9H5\xdf\x14\xa9\xcfV\r\xea}\x98\x04\x8dK,\xb6\xf7;\xaa\xa8\xa5\xad\x7f\x0fCY'
+t2 = f.derive_key_block("A"*48, "C"*32, "B"*32, 72) == 'Ts/q\x83\x88\x10\x9c1Y\xff\xf3vo\xe3\x8aM\x9b\xa3k[J\xeeWXs\xcfTe\x19\xc6\xb1\x0ebj1}\x0c\xca\x97=|\x88W\xd8q\xfb|\x17\x99\nH;\xec\xd2\x15\xabd\xed\xc3\xe0p\xd8\x1eS\xb5\xf4*8\xceE^'
+t3 = f.derive_key_block("C"*48, "A"*32, "B"*32, 72) == 'Q\xde\x06L\xdb\xe9\x9dC\x19\x8a:m@\xce\xbf\xc0\n\xd8\xd4H!#\x06\xad\x929\x85\xc9@\x1f\xb5\xe2)^{c\x94\x06&\xad\xb56\x13^\xd6\xa5\x19\xe7\xed\xd6\x92\xe0O\x0e\xbf\xc6\x97\x9f~\x95\xcf\xb0\xe7a\x1d\xbc]\xf4&Z\x81J'
+t4 = f.derive_key_block("D"*48, "B"*32, "A"*32, 72) == '\xbe\x9a\xc8)\xb5{.H1\x8382\xc2\xdff\xdf@\xda\xde\x88\xe1\xf3\xad9\xcc\x14\xb1\x7f\x90\x00;B)\x8c\xdb\xdbH\xfe=%^\xe9\x83\x0eV\x86\x83\x8d\xeal\x8ea\x08\x9d\xb3\xf3\xf4\xa6[\'j\xda\rT"\x10\xa5Z\n\xc0r\xf3'
+t1 and t2 and t3 and t4
+
+
++ Test compute_master_secret() for TLS 1.0
+= Crypto - compute_master_secret() in TLS 1.0 mode
+from scapy.layers.tls.crypto.prf import PRF
+f = PRF(tls_version=0x301)
+t1 = f.compute_master_secret("A"*48, "B"*32, "C"*32) == "k\\[e\x11\xab\xfe6\trN\x9e\x8d\xb09{\x17\x8d\x9f\xc6_' G\x05\x08}\xf7Q\x8e\xcb\xff\x00\xfc7\xd0\xf0z\xea\x8b\x98%\x90\x89sd\x98\xa1"
+t2 = f.compute_master_secret("A"*48, "C"*32, "B"*32) == 'k\xd2\xf7\x1aqt\xa4~\x9bqf\x0f:\xc4%\x9a\x07\x17\x14\xf4\xdf&)*\x1c\x9c8\x8em\xe1\x13\x17\xa7\xd2\x051Q<M~\xc2a\x85\x82\xe6\xd7.['
+t3 = f.compute_master_secret("C"*48, "A"*32, "B"*32) == '\xe57\xae.,B\xeb(/?\xf4tR#\xd0\xa9"\xf7-\x9d\x0e\xd7\xd9\x1c\x1f\x9b\x95\xe6\xd0\x0e(\x06W7s(^"x\xbb\xdb\xb6\xae\xf75J\x0f\xbf'
+t4 = f.compute_master_secret("D"*48, "B"*32, "A"*32) == '\xeb3\xf5Ty\x08xqP\x01p\x12\x95\xd4\xf5y{\xe7\xea5\nS\xb1T\xea\xe3d\x8b\xd7\xb89\xcf\xb9\xe0l\x95d\xbd-\x97\xea\xf20n\x96t\xfe\xff'
+t1 and t2 and t3 and t4
+
+
++ Test derive_key_block() for TLS 1.0
+= Crypto - derive_key_block() in TLS 1.0 mode
+t1 = f.derive_key_block("A"*48, "B"*32, "C"*32, 72) == '\x06\xccA\xd5\xf3\x9dT`ZC!/\xa0\xbe\x95\x86m\xdb@\x18\xfb\x95\xad\xcd\xac<(K\x88\xacB\x92s\x8d7AVG\xf04\x0be\x8dv\x02\xd6\x03\x7f\xe4\x8eYe\x88\xb7YI\xc2\xf0!\x1dSx\x86\xdeY\x81\x89\x11\xa6\xd9\xd1\xed'
+t2 = f.derive_key_block("A"*48, "C"*32, "B"*32, 72) == "\\@d\x1d9V\xae\xe2'\xf6Q\xc9\xd7\x8beu\xe8u\xd9\xe8\r\x18a\x8c|\xde\x95H\xec\xc5}I\xf9s(e\xe4\x87*s\x98=\x96wsj\xfe\x0euo\x1f\\1hh-\x0f\xda9\x9etk\x0fW\x03\xe2k\xb0\x87Pb3"
+t3 = f.derive_key_block("C"*48, "A"*32, "B"*32, 72) == '\x9c\xaate\x07\x12K\xb2\xc3zT1\xf4\x1fN\xa8\x03\xbd\xcfF_\x0c\x0bF\x14\x8f\xcf\x08c\xa6\x80\x1d\xd8Wh.E\xf5\x9a\xfd\x1d\x8a6\xf7\x950\xf4\xbcm\x89\xa6!\x7fc\x19D\xb4\xcc\x8f\xf7x\x12\xe0q\x17\x84-\xcc[\x7f@p'
+t4 = f.derive_key_block("D"*48, "B"*32, "A"*32, 72) == 't{P+k\xe1\xe5O\xbe]L?$\x8d7O.\xe6\xd6\xa8\x19U\x87\x04%\x13m+_\xb9\x99\x03\xe1\xfd1]*7\x8d\xa0Xx\xa1\xd1\xfe\x0c\xb1\xb1\xa8\xdd\x0c\xb20@v\xb6\xdc\x86d\n\x8a-\x95\xaeL\x97\xfaFjl\xfb^'
+t1 and t2 and t3 and t4
+
+
+###############################################################################
+### Ciphers                                                                 ###
+###############################################################################
+
++ Test RC4
+= Crypto - RC4 stream cipher, encryption/decryption checks from RFC 6229
+
+class _rc4_40_test:
+    k= "\x01\x02\x03\x04\x05"
+    s=("\xb2\x39\x63\x05\xf0\x3d\xc0\x27\xcc\xc3\x52\x4a\x0a\x11\x18\xa8" +
+       "\x69\x82\x94\x4f\x18\xfc\x82\xd5\x89\xc4\x03\xa4\x7a\x0d\x09\x19")
+    s_1024= "\x30\xab\xbc\xc7\xc2\x0b\x01\x60\x9f\x23\xee\x2d\x5f\x6b\xb7\xdf"
+
+class _rc4_128_test:
+    k= "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+    s=("\x9a\xc7\xcc\x9a\x60\x9d\x1e\xf7\xb2\x93\x28\x99\xcd\xe4\x1b\x97"
+       "\x52\x48\xc4\x95\x90\x14\x12\x6a\x6e\x8a\x84\xf1\x1d\x1a\x9e\x1c")
+    s_1024="\xbd\xf0\x32\x4e\x60\x83\xdc\xc6\xd3\xce\xdd\x3c\xa8\xc5\x3c\x16"
+
+def _all_rc4_tests():
+    from scapy.layers.tls.crypto.cipher_stream import (Cipher_RC4_40,
+                                                       Cipher_RC4_128)
+    res = True
+    t = _rc4_40_test
+    c = Cipher_RC4_40(t.k).encrypt("\x00"*(1024+16))
+    res = res and (c[:32] == t.s) and (c[-16:] == t.s_1024)
+    res = res and Cipher_RC4_40(t.k).decrypt(t.s) == "\x00"*32
+    t = _rc4_128_test
+    c = Cipher_RC4_128(t.k).encrypt("\x00"*(1024+16))
+    res = res and (c[:32] == t.s) and (c[-16:] == t.s_1024)
+    res = res and Cipher_RC4_128(t.k).decrypt(t.s) == "\x00"*32
+    return res
+
+_all_rc4_tests()
+
+
++ Test AES-CBC
+= Crypto - AES cipher in CBC mode, checks from RFC 3602
+
+class _aes128cbc_test_1:
+    k= "\x06\xa9\x21\x40\x36\xb8\xa1\x5b\x51\x2e\x03\xd5\x34\x12\x00\x06"
+    p= "Single block msg"
+    c= "\xe3\x53\x77\x9c\x10\x79\xae\xb8\x27\x08\x94\x2d\xbe\x77\x18\x1a"
+    iv="\x3d\xaf\xba\x42\x9d\x9e\xb4\x30\xb4\x22\xda\x80\x2c\x9f\xac\x41"
+
+class _aes128cbc_test_2:
+    k= "\x56\xe4\x7a\x38\xc5\x59\x89\x74\xbc\x46\x90\x3d\xba\x29\x03\x49"
+    p=("\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" +
+       "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" +
+       "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" +
+       "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf")
+    c=("\xc3\x0e\x32\xff\xed\xc0\x77\x4e\x6a\xff\x6a\xf0\x86\x9f\x71\xaa" +
+       "\x0f\x3a\xf0\x7a\x9a\x31\xa9\xc6\x84\xdb\x20\x7e\xb0\xef\x8e\x4e" +
+       "\x35\x90\x7a\xa6\x32\xc3\xff\xdf\x86\x8b\xb7\xb2\x9d\x3d\x46\xad" +
+       "\x83\xce\x9f\x9a\x10\x2e\xe9\x9d\x49\xa5\x3e\x87\xf4\xc3\xda\x55")
+    iv="\x8c\xe8\x2e\xef\xbe\xa0\xda\x3c\x44\x69\x9e\xd7\xdb\x51\xb7\xd9"
+
+class _aes256cbc_test_1:
+    k=("\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81" +
+       "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4")
+    p= "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+    c= "\xf5\x8c\x4c\x04\xd6\xe5\xf1\xba\x77\x9e\xab\xfb\x5f\x7b\xfb\xd6"
+    iv="\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+
+class _aes256cbc_test_2:
+    k=("\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81" +
+       "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4")
+    p= "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10"
+    c= "\xb2\xeb\x05\xe2\xc3\x9b\xe9\xfc\xda\x6c\x19\x07\x8c\x6a\x9d\x1b"
+    iv="\x39\xF2\x33\x69\xA9\xD9\xBA\xCF\xA5\x30\xE2\x63\x04\x23\x14\x61"
+
+def _all_aes_cbc_tests():
+    from scapy.layers.tls.crypto.cipher_block import (Cipher_AES_128_CBC,
+                                                      Cipher_AES_256_CBC)
+    res = True
+    for t in [_aes128cbc_test_1, _aes128cbc_test_2]:
+        tmp = (Cipher_AES_128_CBC(t.k, t.iv).encrypt(t.p) == t.c and
+               Cipher_AES_128_CBC(t.k, t.iv).decrypt(t.c) == t.p)
+        res = res and tmp
+    for t in [_aes256cbc_test_1, _aes256cbc_test_2]:
+        tmp = (Cipher_AES_256_CBC(t.k, t.iv).encrypt(t.p) == t.c and
+               Cipher_AES_256_CBC(t.k, t.iv).decrypt(t.c) == t.p)
+        res = res and tmp
+    return res
+
+_all_aes_cbc_tests()
+
+
++ Test AES-GCM
+= Crypto - AES cipher in GCM mode, auth_encrypt() and auth_decrypt() checks
+~ combined_modes
+#https://tools.ietf.org/html/draft-mcgrew-gcm-test-01
+
+class _aes128gcm_test_1:
+    k= "\x4c\x80\xcd\xef\xbb\x5d\x10\xda\x90\x6a\xc7\x3c\x36\x13\xa6\x34"
+    n= "\x22\x43\x3c\x64\x48\x55\xec\x7d\x3a\x23\x4b\xfd"
+    p=("\x08\x00\xc6\xcd\x02\x00\x07\x00\x61\x62\x63\x64\x65\x66\x67\x68" +
+       "\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x01\x02\x02\x01")
+    a= "\x00\x00\x43\x21\x87\x65\x43\x21\x00\x00\x00\x07"
+    ct=("\x74\x75\x2e\x8a\xeb\x5d\x87\x3c\xd7\xc0\xf4\xac\xc3\x6c\x4b\xff" +
+       "\x84\xb7\xd7\xb9\x8f\x0c\xa8\xb6\xac\xda\x68\x94\xbc\x61\x90\x69" +
+       "\xef\x9c\xbc\x28\xfe\x1b\x56\xa7\xc4\xe0\xd5\x8c\x86\xcd\x2b\xc0")
+
+class _aes128gcm_test_2:
+    k= "\x3d\xe0\x98\x74\xb3\x88\xe6\x49\x19\x88\xd0\xc3\x60\x7e\xae\x1f"
+    n= "\x57\x69\x0e\x43\x4e\x28\x00\x00\xa2\xfc\xa1\xa3"
+    p=("\x45\x00\x00\x30\xda\x3a\x00\x00\x80\x01\xdf\x3b\xc0\xa8\x00\x05" +
+       "\xc0\xa8\x00\x01\x08\x00\xc6\xcd\x02\x00\x07\x00\x61\x62\x63\x64" +
+       "\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74" +
+       "\x01\x02\x02\x01")
+    a= "\x3f\x7e\xf6\x42\x10\x10\x10\x10\x10\x10\x10\x10"
+    ct=("\xfb\xa2\xca\xa8\xc6\xc5\xf9\xf0\xf2\x2c\xa5\x4a\x06\x12\x10\xad" +
+       "\x3f\x6e\x57\x91\xcf\x1a\xca\x21\x0d\x11\x7c\xec\x9c\x35\x79\x17" +
+       "\x65\xac\xbd\x87\x01\xad\x79\x84\x5b\xf9\xfe\x3f\xba\x48\x7b\xc9" +
+       "\x63\x21\x93\x06\x84\xee\xca\xdb\x56\x91\x25\x46\xe7\xa9\x5c\x97" +
+       "\x40\xd7\xcb\x05")
+
+class _aes256gcm_test_1:
+    k=("\x6c\x65\x67\x61\x6c\x69\x7a\x65\x6d\x61\x72\x69\x6a\x75\x61\x6e" +
+       "\x61\x61\x6e\x64\x64\x6f\x69\x74\x62\x65\x66\x6f\x72\x65\x69\x61")
+    n= "\x74\x75\x72\x6e\x33\x30\x21\x69\x67\x65\x74\x6d"
+    p=("\x45\x00\x00\x30\xda\x3a\x00\x00\x80\x01\xdf\x3b\xc0\xa8\x00\x05" +
+       "\xc0\xa8\x00\x01\x08\x00\xc6\xcd\x02\x00\x07\x00\x61\x62\x63\x64" +
+       "\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74" +
+       "\x01\x02\x02\x01")
+    a= "\x79\x6b\x69\x63\xff\xff\xff\xff\xff\xff\xff\xff"
+    ct=("\xf9\x7a\xb2\xaa\x35\x6d\x8e\xdc\xe1\x76\x44\xac\x8c\x78\xe2\x5d" +
+       "\xd2\x4d\xed\xbb\x29\xeb\xf1\xb6\x4a\x27\x4b\x39\xb4\x9c\x3a\x86" +
+       "\x4c\xd3\xd7\x8c\xa4\xae\x68\xa3\x2b\x42\x45\x8f\xb5\x7d\xbe\x82" +
+       "\x1d\xcc\x63\xb9\xd0\x93\x7b\xa2\x94\x5f\x66\x93\x68\x66\x1a\x32" +
+       "\x9f\xb4\xc0\x53")
+
+class _aes256gcm_test_2:
+    # this funny plaintext is not our deed
+    k=("\xab\xbc\xcd\xde\xf0\x01\x12\x23\x34\x45\x56\x67\x78\x89\x9a\xab" +
+       "\xab\xbc\xcd\xde\xf0\x01\x12\x23\x34\x45\x56\x67\x78\x89\x9a\xab")
+    n= "\x73\x61\x6c\x74\x61\x6e\x64\x01\x69\x76\x65\x63"
+    p=("\x63\x69\x73\x63\x6f\x01\x72\x75\x6c\x65\x73\x01\x74\x68\x65\x01" +
+       "\x6e\x65\x74\x77\x65\x01\x64\x65\x66\x69\x6e\x65\x01\x74\x68\x65" +
+       "\x74\x65\x63\x68\x6e\x6f\x6c\x6f\x67\x69\x65\x73\x01\x74\x68\x61" +
+       "\x74\x77\x69\x6c\x6c\x01\x64\x65\x66\x69\x6e\x65\x74\x6f\x6d\x6f" +
+       "\x72\x72\x6f\x77\x01\x02\x02\x01")
+    a= "\x17\x40\x5e\x67\x15\x6f\x31\x26\xdd\x0d\xb9\x9b"
+    ct=("\xd4\xb7\xed\x86\xa1\x77\x7f\x2e\xa1\x3d\x69\x73\xd3\x24\xc6\x9e" +
+       "\x7b\x43\xf8\x26\xfb\x56\x83\x12\x26\x50\x8b\xeb\xd2\xdc\xeb\x18" +
+       "\xd0\xa6\xdf\x10\xe5\x48\x7d\xf0\x74\x11\x3e\x14\xc6\x41\x02\x4e" +
+       "\x3e\x67\x73\xd9\x1a\x62\xee\x42\x9b\x04\x3a\x10\xe3\xef\xe6\xb0" +
+       "\x12\xa4\x93\x63\x41\x23\x64\xf8\xc0\xca\xc5\x87\xf2\x49\xe5\x6b" +
+       "\x11\xe2\x4f\x30\xe4\x4c\xcc\x76")
+
+def _all_aes_gcm_tests():
+    from scapy.layers.tls.crypto.cipher_aead import (Cipher_AES_128_GCM,
+                                                     Cipher_AES_256_GCM)
+    res = True
+    ciphers = []
+    for t in [_aes128gcm_test_1, _aes128gcm_test_2]:
+        c = Cipher_AES_128_GCM(key=t.k, salt=t.n[:4],
+                               nonce_explicit=pkcs_os2ip(t.n[4:]))
+        ne = t.n[-c.nonce_explicit_len:]
+        tup = ne, t.p, t.ct[-c.tag_len:]
+        tmp1 = c.auth_decrypt(t.a, ne + t.ct, add_length=False) == tup
+        tmp2 = c.auth_encrypt(t.p, t.a) == (ne + t.ct)
+        res = res and tmp1 and tmp2
+    for t in [_aes256gcm_test_1, _aes256gcm_test_2]:
+        c = Cipher_AES_256_GCM(key=t.k, salt=t.n[:4],
+                               nonce_explicit=pkcs_os2ip(t.n[4:]))
+        ne = t.n[-c.nonce_explicit_len:]
+        tup = ne, t.p, t.ct[-c.tag_len:]
+        tmp1 = c.auth_decrypt(t.a, ne + t.ct, add_length=False) == tup
+        tmp2 = c.auth_encrypt(t.p, t.a) == (ne + t.ct)
+        res = res and tmp1 and tmp2
+    return res
+
+_all_aes_gcm_tests()
+
+
+#XXX CCM remains to be added to the cryptography library
+#+ Test AES-CCM
+#= Crypto - AES cipher in CCM mode, checks from IEEE P1619.1
+#~ combined_modes
+#
+#class _aes256ccm_test_1:
+#    k= "\0"*32
+#    n= "\0"*12
+#    p= "\0"*16
+#    a= ""
+#    ct=("\xc1\x94\x40\x44\xc8\xe7\xaa\x95\xd2\xde\x95\x13\xc7\xf3\xdd\x8c" +
+#       "\x4b\x0a\x3e\x5e\x51\xf1\x51\xeb\x0f\xfa\xe7\xc4\x3d\x01\x0f\xdb")
+#
+#class _aes256ccm_test_2:
+#    k=("\xfb\x76\x15\xb2\x3d\x80\x89\x1d\xd4\x70\x98\x0b\xc7\x95\x84\xc8" +
+#       "\xb2\xfb\x64\xce\x60\x97\x87\x8d\x17\xfc\xe4\x5a\x49\xe8\x30\xb7")
+#    n= "\xdb\xd1\xa3\x63\x60\x24\xb7\xb4\x02\xda\x7d\x6f"
+#    p= "\xa9"
+#    a= "\x36"
+#    ct="\x9d\x32\x61\xb1\xcf\x93\x14\x31\xe9\x9a\x32\x80\x67\x38\xec\xbd\x2a"
+#
+#class _aes256ccm_test_3:
+#    k=("\xfb\x76\x15\xb2\x3d\x80\x89\x1d\xd4\x70\x98\x0b\xc7\x95\x84\xc8" +
+#       "\xb2\xfb\x64\xce\x60\x97\x8f\x4d\x17\xfc\xe4\x5a\x49\xe8\x30\xb7")
+#    n= "\xdb\xd1\xa3\x63\x60\x24\xb7\xb4\x02\xda\x7d\x6f"
+#    p= "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e"
+#    a= ""
+#    ct=("\xcc\x88\x12\x61\xc6\xa7\xfa\x72\xb9\x6a\x17\x39\x17\x6b\x27\x7f" +
+#       "\x34\x72\xe1\x14\x5f\x2c\x0c\xbe\x14\x63\x49\x06\x2c\xf0\xe4\x23")
+#
+#class _aes256ccm_test_4:
+#    k=("\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" +
+#       "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f")
+#    n= "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b"
+#    p=("\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" +
+#       "\x30\x31\x32\x33\x34\x35\x36\x37")
+#    a=("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
+#       "\x10\x11\x12\x13")
+#    ct=("\x04\xf8\x83\xae\xb3\xbd\x07\x30\xea\xf5\x0b\xb6\xde\x4f\xa2\x21" +
+#       "\x20\x34\xe4\xe4\x1b\x0e\x75\xe5\x9b\xba\x3f\x3a\x10\x7f\x32\x39" +
+#       "\xbd\x63\x90\x29\x23\xf8\x03\x71")
+#
+#def _all_aes_ccm_tests():
+#    from scapy.layers.tls.crypto.cipher_aead import Cipher_AES_256_CCM
+#    res = True
+#    ciphers = []
+#    for t in [_aes256ccm_test_1, _aes256ccm_test_2,
+#              _aes256ccm_test_3, _aes256ccm_test_4]:
+#        c = Cipher_AES_256_CCM(key=t.k, salt=t.n[:4],
+#                               nonce_explicit_init=pkcs_os2ip(t.n[4:]))
+#        ne = t.n[-c.nonce_explicit_len:]
+#        tup = ne, t.p, t.ct[-c.tag_len:]
+#        tmp1 = c.auth_decrypt(t.a, ne + t.ct, add_length=False) == tup
+#        tmp2 = c.auth_encrypt(t.p, t.a) == (ne + t.ct)
+#        res = res and tmp1 and tmp2
+#    return res
+#
+#_all_aes_ccm_tests()
+
+
++ Test camellia
+= Crypto - Camellia cipher, encryption/decryption checks
+
+class _Camellia128_test:
+    k= "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10"
+    p= "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10"
+    c= "\x67\x67\x31\x38\x54\x96\x69\x73\x08\x57\x06\x56\x48\xea\xbe\x43"
+    iv="\0"*16
+
+class _Camellia256_test:
+    k=("\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10" +
+       "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff")
+    p= "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10"
+    c= "\x9a\xcc\x23\x7d\xff\x16\xd7\x6c\x20\xef\x7c\x91\x9e\x3a\x75\x09"
+    iv="\0"*16
+
+def _all_camellia_tests():
+    from scapy.layers.tls.crypto.cipher_block import (Cipher_CAMELLIA_128_CBC,
+                                                      Cipher_CAMELLIA_256_CBC)
+    res = True
+    t = _Camellia128_test
+    tmp = (Cipher_CAMELLIA_128_CBC(t.k, t.iv).encrypt(t.p) == t.c and
+           Cipher_CAMELLIA_128_CBC(t.k, t.iv).decrypt(t.c) == t.p)
+    res = res and tmp
+    t = _Camellia256_test
+    tmp = (Cipher_CAMELLIA_256_CBC(t.k, t.iv).encrypt(t.p) == t.c and
+           Cipher_CAMELLIA_256_CBC(t.k, t.iv).decrypt(t.c) == t.p)
+    res = res and tmp
+    return res
+
+_all_camellia_tests()
+
+
+###############################################################################
+############################ Reading test session #############################
+###############################################################################
+
+# These packets come from a random TLS thread captured
+# during a github connection from a Mozilla Firefox client.
+
++ Test strings
+= Reading test session - Loading unparsed TLS records
+p1_ch = '\x16\x03\x01\x00\xd5\x01\x00\x00\xd1\x03\x03\x17\xf2M\xc3|\x19\xdb\xc3<\xb5J\x0b\x8d5\x81\xc5\xce\t 2\x08\xd8\xec\xd1\xf8"B\x9cW\xd0\x16v\x00\x00\x16\xc0+\xc0/\xc0\n\xc0\t\xc0\x13\xc0\x14\x003\x009\x00/\x005\x00\n\x01\x00\x00\x92\x00\x00\x00\x1f\x00\x1d\x00\x00\x1acamo.githubusercontent.com\xff\x01\x00\x01\x00\x00\n\x00\x08\x00\x06\x00\x17\x00\x18\x00\x19\x00\x0b\x00\x02\x01\x00\x00#\x00\x003t\x00\x00\x00\x10\x00)\x00\'\x05h2-16\x05h2-15\x05h2-14\x02h2\x08spdy/3.1\x08http/1.1\x00\x05\x00\x05\x01\x00\x00\x00\x00\x00\r\x00\x16\x00\x14\x04\x01\x05\x01\x06\x01\x02\x01\x04\x03\x05\x03\x06\x03\x02\x03\x04\x02\x02\x02'
+p2_sh = '\x16\x03\x03\x00T\x02\x00\x00P\x03\x03F\x07n\xe2\x0c\x97g\xb7o\xb6\x9b\x14\x19\xbd\xdd1\x80@\xaaQ+\xc2,\x19\x15"\x82\xe8\xc5,\xe8\x12\x00\xc0/\x00\x00(\x00\x00\x00\x00\xff\x01\x00\x01\x00\x00\x0b\x00\x04\x03\x00\x01\x02\x00#\x00\x00\x00\x05\x00\x00\x00\x10\x00\x0b\x00\t\x08http/1.1'
+p3_cert = '\x16\x03\x03\nu\x0b\x00\nq\x00\nn\x00\x05\xb30\x82\x05\xaf0\x82\x04\x97\xa0\x03\x02\x01\x02\x02\x10\x07z]\xc36#\x01\xf9\x89\xfeT\xf7\xf8o>d0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x000p1\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x150\x13\x06\x03U\x04\n\x13\x0cDigiCert Inc1\x190\x17\x06\x03U\x04\x0b\x13\x10www.digicert.com1/0-\x06\x03U\x04\x03\x13&DigiCert SHA2 High Assurance Server CA0\x1e\x17\r160120000000Z\x17\r170406120000Z0j1\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x130\x11\x06\x03U\x04\x08\x13\nCalifornia1\x160\x14\x06\x03U\x04\x07\x13\rSan Francisco1\x150\x13\x06\x03U\x04\n\x13\x0cFastly, Inc.1\x170\x15\x06\x03U\x04\x03\x13\x0ewww.github.com0\x82\x01"0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x000\x82\x01\n\x02\x82\x01\x01\x00\xfb\xd5\x94\n\n\xe0P\xdc\x0f\xfc\x90\xb7qG\x9f,\x05\xde\x0e\x9a\xbc*\x8f\xd4\xf2\x9f\x08F\xf9\xf2\xd1\x18\xb4#\xa5*\xd2\xdf\x91?\xf9\xc5\xd0\xb2@\xbd\xd6\xbc@v.\x8d\xd8\x1e\r7\x8fz\x90W\xef\xe3\xa2\xc0\x11a\x03F\x0e\xfa\xb37\x0bf|!\x16\x8d\xfe/^.Y\xfec\':\xf3\xeds\xf8Mt\xb3Q\x17u\x9a\xed\x0ck\xcd\xe8\xc1\xea\xca\x01\xacu\xf9\x17)\xf0KP\x9dAdHl\xf6\xc0g}\xc8\xea\xdeHy\x81\x97A\x02\xb7F\xf6^M\xa5\xd9\x90\x86\xd7\x1ehQ\xac>%\xae\'\x11\xb1G4\xb8\x8b\xdeoyA\xd6\x92\x13)\x11\x80\xc4\x10\x17\\\x0clj\x02\xbb\xd0\n\xfc\xd2\x96x\x1d\xb6\xd4\x02\x7f\x1f\x0eR@Sop@\xda\x89)O\x0c\t~\xa3\xec\xc5W\xad\x03\xaa\x91\xedC\\\xf9\xf5[\xe8\xa1\xf0\xbem\x1b\xce-\xabC|p\xdc?\xec\xc9\x11\xf0t\xc9)\xa1P\xd0<)8\xdc\x7fV\xb9\xf8\x1f\x04\xa4^\x9f\xce\xdd\x17\x02\x03\x01\x00\x01\xa3\x82\x02I0\x82\x02E0\x1f\x06\x03U\x1d#\x04\x180\x16\x80\x14Qh\xff\x90\xaf\x02\x07u<\xcc\xd9edb\xa2\x12\xb8Yr;0\x1d\x06\x03U\x1d\x0e\x04\x16\x04\x14d\xbfD\xb3F\t\x9b\xcfZ\x1dqI\xa2\x04r\x8b\x884\x84#0{\x06\x03U\x1d\x11\x04t0r\x82\x0ewww.github.com\x82\x0c*.github.com\x82\ngithub.com\x82\x0b*.github.io\x82\tgithub.io\x82\x17*.githubusercontent.com\x82\x15githubusercontent.com0\x0e\x06\x03U\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x05\xa00\x1d\x06\x03U\x1d%\x04\x160\x14\x06\x08+\x06\x01\x05\x05\x07\x03\x01\x06\x08+\x06\x01\x05\x05\x07\x03\x020u\x06\x03U\x1d\x1f\x04n0l04\xa02\xa00\x86.http://crl3.digicert.com/sha2-ha-server-g5.crl04\xa02\xa00\x86.http://crl4.digicert.com/sha2-ha-server-g5.crl0L\x06\x03U\x1d \x04E0C07\x06\t`\x86H\x01\x86\xfdl\x01\x010*0(\x06\x08+\x06\x01\x05\x05\x07\x02\x01\x16\x1chttps://www.digicert.com/CPS0\x08\x06\x06g\x81\x0c\x01\x02\x020\x81\x83\x06\x08+\x06\x01\x05\x05\x07\x01\x01\x04w0u0$\x06\x08+\x06\x01\x05\x05\x070\x01\x86\x18http://ocsp.digicert.com0M\x06\x08+\x06\x01\x05\x05\x070\x02\x86Ahttp://cacerts.digicert.com/DigiCertSHA2HighAssuranceServerCA.crt0\x0c\x06\x03U\x1d\x13\x01\x01\xff\x04\x020\x000\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00O\x16\xd1t\xf8>\xa3\x8f~\xf7\xaf\xcf\xfa\xb6\xdd\xa7\x88\x9e\xf8!\xad|(\x14\xb9\xb4\xffg\xd0\xb9\xe2O\x81}\x03\xb4\x9d\xbcU\x80$\x8c\xe5fP\xb8\xb8(\xd9\x0f\xb4\x95\xccb\xb2\x87|\xcf\x16^SH\xf9\xc2\xf8\x90 \xdc\x0e\x96\x7f\xe27\xcfA\xc7uf\r\x1c\xa7M\xee\x02\xaa\x1b\x00\xc0\xea\x0e\xd4Df\x08\t\xac\x00\x90pc\xfa\xcd\xaf\x89\x8a\xdbj|z\xb0k\xa8\xc5\xb4\x9d\x85\xd8S\x93E\xcar>\xa4\xd4\xe3\xa28J\x0f\x82\x08\xf0\xf3U\xf0m\xb21l\x189\xbf\xee\xe3\xe5\x8f\xcd@\x07\x0b\xd0\xe9e\xda\xd6LA\xff[\xafB\xaf\xf2\xb1F\xa1\xacX\xfc)\x80\xcb\xf6Z\xa6\xaf\xf26\x93\xdf\x92q\xa95\xe3:XP\xab::|\xd9\xf7y\x83\x9e\t\xfe\x0f\x90,Y+\x07$Z<\xb5\xd2\xa0\xdaE\xb8\xe1\xc0\x03\x07\x00h\xf6L\xfa\xe2v[\xce\x8f\xfe\xd0\xcb%\xf9\x9b\xcb\xa9\xffU\x12\xf3=_En2\xa0$\x8e\xb7\xa5vo\x0b\x87\xe9\x00\x04\xb50\x82\x04\xb10\x82\x03\x99\xa0\x03\x02\x01\x02\x02\x10\x04\xe1\xe7\xa4\xdc\\\xf2\xf3m\xc0+B\xb8]\x15\x9f0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x000l1\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x150\x13\x06\x03U\x04\n\x13\x0cDigiCert Inc1\x190\x17\x06\x03U\x04\x0b\x13\x10www.digicert.com1+0)\x06\x03U\x04\x03\x13"DigiCert High Assurance EV Root CA0\x1e\x17\r131022120000Z\x17\r281022120000Z0p1\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x150\x13\x06\x03U\x04\n\x13\x0cDigiCert Inc1\x190\x17\x06\x03U\x04\x0b\x13\x10www.digicert.com1/0-\x06\x03U\x04\x03\x13&DigiCert SHA2 High Assurance Server CA0\x82\x01"0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x000\x82\x01\n\x02\x82\x01\x01\x00\xb6\xe0/\xc2$\x06\xc8m\x04_\xd7\xef\nd\x06\xb2}"&e\x16\xaeB@\x9b\xce\xdc\x9f\x9fv\x07>\xc30U\x87\x19\xb9O\x94\x0eZ\x94\x1fUV\xb4\xc2\x02*\xaf\xd0\x98\xee\x0b@\xd7\xc4\xd0;r\xc8\x14\x9e\xef\x90\xb1\x11\xa9\xae\xd2\xc8\xb8C:\xd9\x0b\x0b\xd5\xd5\x95\xf5@\xaf\xc8\x1d\xedM\x9c_W\xb7\x86Ph\x99\xf5\x8a\xda\xd2\xc7\x05\x1f\xa8\x97\xc9\xdc\xa4\xb1\x82\x84-\xc6\xad\xa5\x9c\xc7\x19\x82\xa6\x85\x0f^DX*7\x8f\xfd5\xf1\x0b\x08\'2Z\xf5\xbb\x8b\x9e\xa4\xbdQ\xd0\'\xe2\xdd;B3\xa3\x05(\xc4\xbb(\xcc\x9a\xac+#\rx\xc6{\xe6^q\xb7J>\x08\xfb\x81\xb7\x16\x16\xa1\x9d#\x12M\xe5\xd7\x92\x08\xacu\xa4\x9c\xba\xcd\x17\xb2\x1eD5e\x7fS%9\xd1\x1c\n\x9ac\x1b\x19\x92th\n7\xc2\xc2RH\xcb9Z\xa2\xb6\xe1]\xc1\xdd\xa0 \xb8!\xa2\x93&o\x14J!A\xc7\xedm\x9b\xf2H/\xf3\x03\xf5\xa2h\x92S/^\xe3\x02\x03\x01\x00\x01\xa3\x82\x01I0\x82\x01E0\x12\x06\x03U\x1d\x13\x01\x01\xff\x04\x080\x06\x01\x01\xff\x02\x01\x000\x0e\x06\x03U\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x01\x860\x1d\x06\x03U\x1d%\x04\x160\x14\x06\x08+\x06\x01\x05\x05\x07\x03\x01\x06\x08+\x06\x01\x05\x05\x07\x03\x0204\x06\x08+\x06\x01\x05\x05\x07\x01\x01\x04(0&0$\x06\x08+\x06\x01\x05\x05\x070\x01\x86\x18http://ocsp.digicert.com0K\x06\x03U\x1d\x1f\x04D0B0@\xa0>\xa0<\x86:http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl0=\x06\x03U\x1d \x0460402\x06\x04U\x1d \x000*0(\x06\x08+\x06\x01\x05\x05\x07\x02\x01\x16\x1chttps://www.digicert.com/CPS0\x1d\x06\x03U\x1d\x0e\x04\x16\x04\x14Qh\xff\x90\xaf\x02\x07u<\xcc\xd9edb\xa2\x12\xb8Yr;0\x1f\x06\x03U\x1d#\x04\x180\x16\x80\x14\xb1>\xc3i\x03\xf8\xbfG\x01\xd4\x98&\x1a\x08\x02\xefcd+\xc30\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00\x18\x8a\x95\x89\x03\xe6m\xdf\\\xfc\x1dh\xeaJ\x8f\x83\xd6Q/\x8dkD\x16\x9e\xacc\xf5\xd2nl\x84\x99\x8b\xaa\x81q\x84[\xed4N\xb0\xb7y\x92)\xcc-\x80j\xf0\x8e \xe1y\xa4\xfe\x03G\x13\xea\xf5\x86\xcaYq}\xf4\x04\x96k\xd3YX=\xfe\xd31%\\\x188\x84\xa3\xe6\x9f\x82\xfd\x8c[\x981N\xcdx\x9e\x1a\xfd\x85\xcbI\xaa\xf2\'\x8b\x99r\xfc>\xaa\xd5A\x0b\xda\xd56\xa1\xbf\x1cnGI\x7f^\xd9H|\x03\xd9\xfd\x8bI\xa0\x98&B@\xeb\xd6\x92\x11\xa4d\nWT\xc4\xf5\x1d\xd6\x02^k\xac\xee\xc4\x80\x9a\x12r\xfaV\x93\xd7\xff\xbf0\x85\x060\xbf\x0b\x7fN\xffW\x05\x9d$\xed\x85\xc3+\xfb\xa6u\xa8\xac-\x16\xef}y\'\xb2\xeb\xc2\x9d\x0b\x07\xea\xaa\x85\xd3\x01\xa3 (AYC(\xd2\x81\xe3\xaa\xf6\xec{;w\xb6@b\x80\x05AE\x01\xef\x17\x06>\xde\xc03\x9bg\xd3a.r\x87\xe4i\xfc\x12\x00W@\x1ep\xf5\x1e\xc9\xb4'
+p4_certstat_ske_shd = '\x16\x03\x03\x01\xdf\x16\x00\x01\xdb\x01\x00\x01\xd70\x82\x01\xd3\n\x01\x00\xa0\x82\x01\xcc0\x82\x01\xc8\x06\t+\x06\x01\x05\x05\x070\x01\x01\x04\x82\x01\xb90\x82\x01\xb50\x81\x9e\xa2\x16\x04\x14Qh\xff\x90\xaf\x02\x07u<\xcc\xd9edb\xa2\x12\xb8Yr;\x18\x0f20160914121000Z0s0q0I0\t\x06\x05+\x0e\x03\x02\x1a\x05\x00\x04\x14\xcf&\xf5\x18\xfa\xc9~\x8f\x8c\xb3B\xe0\x1c/j\x10\x9e\x8e_\n\x04\x14Qh\xff\x90\xaf\x02\x07u<\xcc\xd9edb\xa2\x12\xb8Yr;\x02\x10\x07z]\xc36#\x01\xf9\x89\xfeT\xf7\xf8o>d\x80\x00\x18\x0f20160914121000Z\xa0\x11\x18\x0f20160921112500Z0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00\x90\xef\xf9\x15U\x88\xac@l\xf6n\x04C/\x1a\xf5\xbc[Xi\xd9U\xbe\'\xd3\xb7\xf5\xbb\t\xd8\xb1Tw\x9c2\xac\x7f\x88\xba\x98\xe4\xa13\xf4\xdc\xea\xf3\xacX\xe4,E\xf5\xa9\xc3\xf4B-N\xe0\x89D[\xbe\n\xc2h\x9ar\xfd\'.\xc8,\xed\x83\xc2\xf0\x89_\x8c\xc3\xe7\x8a\xad\xa4\x14\x03\x96\x02\xc4\xa8\xc8\x90\x96%X\x80\x95\x02\x9d_\xc82;m\xe9\x15\x00\xa8\x00\xb9\x01\xe3aN&\xe4\xd5\x8a\xc4w7\x0b\xc3~\xc5\xb1M\x10~T\x9e\x1d\xf6\x06\xf8\x12sTg\x14b_\xe7\xc04\xb4\xa3\xd2\x8f\xe6\xa6\xc4\x01q\x03j\xc8\xd4\xc7\x89\xdde\x99\x1a\xd9\x02\xe7\x17\xd1\xf40P\xef\xf6$\xee\xfad\xf4\xeb\xc8\xf7\x0bRL\x8b\xa5x\xe4R2\xe9\xc2\xfcB\nh\x93\xf7\x0ep4h\xeb\x17\x83\xc8\x88!\xc3W\x94WG\xfe3\x15C0qE&A\x99\xa8}\x1a\xda"\xa9O\xba\x90W_W\xado\x1c\xf0`g7\xbb$\x91o\xec\xdd\xbd\x9e\x8bb\xfc\x16\x03\x03\x01M\x0c\x00\x01I\x03\x00\x17A\x04\xc3\x9d\x1cD\xcb\x85?dU\x9eg\xc9\x90\xd8\x80N|F\x98\x0cA\x07\xdfg\xa2\xfb_z\xe4\x9b\xf6\x06\xf3L\x82KJ8\x0e\x1a\x13\x97;:\x12\rdeu\xb5\x9f\x8d\xaa\xfc\x0f\xacb\x0e\xadVX\x19\x03u\x06\x01\x01\x00y\x8aQ\x11\x94\x91\x7f\xf7\xa3#o.\x11\x1d\xb3K\xede~0\xfb\xaf\x92\xfb\xfdY\x98n\x17$\xae\xf6\x16\x14\x13J;\x1cm7\xfa;\xc8G\xa6\x1a}{\xc2\xa5\x1b\xc5\x1c\xb5\x86\x18\x18Z\xa71\x86\x0b-\xa7/q\x89+\xc7$\xbb\xf2 \x17\xc8`\xbbt[j\x9f\x83\x88\xc0\x8d\xcf4fu1\xc3\xea:B\r\xc6\xc9\x12jP\x0c- \x17\x17t\x10\x17)e\xbe\xaao\xe5@\xd2\xcc\xa5\x89mRy\xfapc~\xa6\x84\x80\xbc4\xb4B\xcb\x92\x86\xad\xf6`9j\xf0\x8ee\xc0|\xfd\xdb\xde!\xceH\x0e\x9c\xfb\x85#\x9f\xb7\xccT\x96\xe0 \xfet-\xd8yUs\xe7m\x94\x07\xbc]~\x99\xd3\x93\xfb\\\xfc@B\x14w\xce\xe8n\x14\xd4\xcc\x07\xe5\xb5@j\x17IQ\xcfub\xcf\xa2\xde\xcaU\xb3 \x8b\xdb\x10Y\x0cS\xc7\x0b\xd8BP\xfeX!\x17\x94\x80\xedu\xf8M\xa7r\xc3\x04\xf4\xd6\xb7\x99\xd1=\x922\xf9\x0b\x9f\xe7\x1b\x932`15\xef\x16\x03\x03\x00\x04\x0e\x00\x00\x00'
+p5_cke_ccs_fin = "\x16\x03\x03\x00F\x10\x00\x00BA\x04\xd2\x07\xce\xa9v\xd8\x1d\x18\x9bN\xe1\x83U\x8c\x8f\xd5a\x0f\xe5_\x9d\x0f\x8c\x9dT\xf6\xa9\x18'a\x8fHH@\x0c\xd4D\x801\x92\x07\xf3\x95\xa9W\x18\xfc\xb7J\xe6j\xbb\xac\x0f\x86\xae\n+\xd5\xb9\xdc\x86[\xe7\x14\x03\x03\x00\x01\x01\x16\x03\x03\x00(\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xcb,\x8cM\xfd\xbc9\xaa\x05\xf3\xd3\xf3Z\x8a-\xc7^\xc1\x8e\x81M\xff\x00\x0f}G\xf2\x8c\xab\n="
+p6_tick_ccs_fin = "\x16\x03\x03\x00\xca\x04\x00\x00\xc6\x00\x00\x04\xb0\x00\xc0c\xccwJ\x00\xdb,B.\x8fv#\xdd\xa9\xaeS\x90S \xb7(^\x0c\xed\n\xaeM\x0bN\xba\xb4\x8a4d\x85\x88 iN\xc9\xd1\xbe\xac\xe2Wb\xc9N\xf3\x85\xbf\xb7j\xa4IB\x8a\x1b\xe4\x8d\x1f\x148%\xd7R3\x0f4\rh\x8f\xccBj\xb5\r\xfa\xc1f\r?f\xc4\x0f_q9\xe1\x07B\x038\xb4}\xbb\xb0\xfc\x0eG\xf2\t&\x13\x98\xcb\xfc\xf6\xf4\xeb\x99!\t]\xe2\xd9-J\xe4\xdbK\xa1\xe5\xf0\t\xdfX\x0c\xb3\r\xf9\x18\xfb}\xd9\nhW1\xfc\x1c\x08DJ,\xa6#\xb0\x15\x16(&\xfdP\x8a%\xeb\xc2\xdd\xd8\xa2/\xbd$\xc3\x14\xfb\xf3\x86\xa3\xceO\x18\x9f\xfdS|'\x11\x02\xc8\xa6eW\xbdo*y\xf3.\xcf\x04\x14\x03\x03\x00\x01\x01\x16\x03\x03\x00(\xd8m\x92\t5YZ:7\\)`\xaa`\x7ff\xcd\x10\xa9v\xa3*\x17\x1a\xecguD\xa8\x87$<7+\n\x94\x1e9\x96\xfa"
+p7_data = "\x17\x03\x03\x01\xf6\x00\x00\x00\x00\x00\x00\x00\x01?\x04iy\x00\x04 \\\xd0\xd4\x9eG\x1f\xbf\xa3k\xfe=\xee\xce\x15\xa0%%\x06c}\xf6\xd4\xfb\xa6\xf0\xf6\x0cO\x1c\x9c\x91\xa9\x0b\x88J\xe0z\x94\xcaT\xeb\xc7\xad\x02j\x10\r\xc6\x12\xb9\xb9\x7f<\x84V\xab\x1e\xfc\xe5\x01\xda\xd6G\xf5\xb7\xf2I6\x8b\xc9\xc4a\xd3\x19\xeat\xfc\x9b\xfa\x1e\xe7\x8c\xaa\xb3\xce\xd0\x86G\x9b\x90\xf7\xde\xb1\x8bwM\x93\xa2gS>\xf3\x97\xf1CB\xfb\x8fs\x1e\xff\x83\xf9\x8b\xc0]\xbd\x80Mn3\xff\xa9\xf3)'\xc3S\xc8\xcd:\xbe\xd72B~$\xb2;\xeb+\xa4\xbd\xa9A\xd9 \n\x87\xe9\xe2\xe9\x82\x83M\x19Q\xf2n\x0e\x15\xdf\xb3;0\xdd&R\xb7\x15\x89\xe9O\xd8G7\x7f\xc3\xb8f\xc7\xd3\xc90R\x83\xf3\xd4\x1cd\xe8\xc5\x8d\xe4N(k7\xf0\xb7\xbd\x01\xb3\x9b\x86\xbaC.\x17\x8d\xd0g\xc9\xb1\x01\xfa\x01\xbe\xdbt\xb1u/\x19V\xc6\x08@\xff\xa8n\xe8\xd0\xd6n,\x05\xc9\xc2\xd8g\x19\x03.l\xb4)\xa09\xf9\xe7\x83\x01-\xe8\xf8\xffy\xbf\xf7\xe6\x11\xc5\xf5\x9aG\xb3e \xd85\x0f\x8f\x85H\xea\xc2n\x1eR\xbe\x01\xef\xef\x93\xe7*>\xbd\x84\x8b9HDI\x90\xc4$\x9a\x9aK\x88Ki\n\xa3\xab\xed\x91\xcd\xe8\xb1\xd4\x8e\xbcE\x88\xe8\x05\x16\xd5\xed\x18\x16g>\x04\xd8\x1dB}\x91\x90\xd1\xda\x03\xe1\x972CxtD\x85\xafF|~7D9*U\xad\x0b\xc4#\x06}\xec\xd6\xd3?y\x96\xa4\xb5\xa3\x1d\x1c\xbd\xc9\xc9g\xb12\xc9\x0f\xa1\x03\x12N\x0b\xec\x14\xc9vJ\nM\xa7\xc8h\xd0|(1(\xa3\x98@nH\n\x0b\xa80\x00\x02\xb7\x06Z\xd4M\xdc!AV\xe2\xa7*\xc3\x90U\xee\xd0\xb2\x05\xa3w\xe1\xe2\xbe\x1e\xbe\xd4u\xb1\xa1z\x1e\x1c\x15%7\xdd\xf9\xb9~\x02\xf9s\x0c1\xfb;\xab\xf1\x1e\xaf\x06\x8c\xafe\x00\x15e5\xac\xd7]>\x1dLb5\x8e+\x01n\xcb\x19\xcc\x17Ey\xc8"
+
+
++ Test TLS
+= Reading test session - TLS parsing (no encryption) does not throw any error
+# We will need to distinguish between connection ends. See next XXX below.
+t1 = TLS(p1_ch)
+t2 = TLS(p2_sh, tls_session=t1.tls_session)
+t3 = TLS(p3_cert, tls_session=t1.tls_session)
+t4 = TLS(p4_certstat_ske_shd, tls_session=t1.tls_session)
+
+
++ Test TLS Record header
+= Reading test session - TLS Record header
+# We leave the possibility for some attributes to be either '' or None.
+assert(t1.type == 0x16)
+assert(t1.version == 0x0301)
+assert(t1.len == 213)
+assert(len(t1.msg) == 1)
+assert(not t1.iv)
+assert(not t1.mac)
+assert(not t1.pad and not t1.padlen)
+len(t1.msg) == 1
+
+
++ Test TLS Record __getitem__
+= Reading test session - TLS Record __getitem__
+TLSClientHello in t1
+
++ Test TLS ClientHello
+= Reading test session - ClientHello
+ch = t1.msg[0]
+assert(isinstance(ch, TLSClientHello))
+assert(ch.msgtype == 1)
+assert(ch.msglen == 209)
+assert(ch.version == 0x0303)
+assert(ch.gmt_unix_time == 0x17f24dc3)
+assert(ch.random_bytes == '|\x19\xdb\xc3<\xb5J\x0b\x8d5\x81\xc5\xce\t 2\x08\xd8\xec\xd1\xf8"B\x9cW\xd0\x16v')
+assert(ch.sidlen == 0)
+assert(not ch.sid)
+assert(ch.cipherslen == 22)
+assert(ch.ciphers == [49195, 49199, 49162, 49161, 49171, 49172, 51, 57, 47, 53, 10])
+assert(ch.complen == 1)
+assert(ch.comp == [0])
+
+
++ Test TLS ClientHello Extensions
+= Reading test session - ClientHello extensions
+assert(ch.extlen == 146)
+ext = ch.ext
+assert(len(ext) == 9)
+assert(isinstance(ext[0], TLS_Ext_ServerName))
+assert(ext[0].type == 0)
+assert(ext[0].len == 31)
+assert(ext[0].servernameslen == 29)
+assert(len(ext[0].servernames) == 1)
+assert(ext[0].servernames[0].nametype == 0)
+assert(ext[0].servernames[0].namelen == 26)
+assert(ext[0].servernames[0].servername == "camo.githubusercontent.com")
+assert(isinstance(ext[1], TLS_Ext_RenegotiationInfo))
+assert(not ext[1].renegotiated_connection)
+assert(isinstance(ext[2], TLS_Ext_SupportedEllipticCurves))
+assert(ext[2].ecl == [0x17, 0x18,  0x19])
+assert(isinstance(ext[3], TLS_Ext_SupportedPointFormat))
+assert(ext[3].ecpl == [0])
+assert(isinstance(ext[4], TLS_Ext_SessionTicket))
+assert(not ext[4].ticket)
+assert(isinstance(ext[5], TLS_Ext_NPN))
+assert(ext[5].protocols == [])
+assert(isinstance(ext[6], TLS_Ext_ALPN))
+assert(len(ext[6].protocols) == 6)
+assert(ext[6].protocols[-1].protocol == "http/1.1")
+assert(isinstance(ext[7], TLS_Ext_CSR))
+assert(isinstance(ext[7].req[0], OCSPStatusRequest))
+assert(isinstance(ext[8], TLS_Ext_SignatureAlgorithms))
+assert(len(ext[8].sig_algs) == 10)
+ext[8].sig_algs[-1] == 0x0202
+
+
++ Test TLS ServerHello
+= Reading test session - ServerHello
+assert(TLSServerHello in t2)
+sh = t2.msg[0]
+assert(isinstance(sh, TLSServerHello))
+assert(sh.gmt_unix_time == 0x46076ee2)
+assert(sh.random_bytes == '\x0c\x97g\xb7o\xb6\x9b\x14\x19\xbd\xdd1\x80@\xaaQ+\xc2,\x19\x15"\x82\xe8\xc5,\xe8\x12')
+assert(sh.cipher == 0xc02f)
+assert(len(sh.ext) == 6)
+sh.ext[-1].protocols[-1].protocol == "http/1.1"
+
+
++ Test TLS Certificate
+= Reading test session - Certificate
+cert = t3.msg[0]
+assert(cert.certslen == 2670)
+assert(len(cert.certs) == 2)
+srv_cert = cert.certs[0][1]
+assert(isinstance(srv_cert, Cert))
+assert(srv_cert.serial == 0x077a5dc3362301f989fe54f7f86f3e64)
+srv_cert.subject['commonName'] == 'www.github.com'
+
+
++ Test TLS CertStat-SKE-SHD
+= Reading test session - Multiple TLS layers
+cert_stat = t4.msg[0]
+ske = t4.payload.msg[0]
+shd = t4.payload.payload.msg[0]
+isinstance(t4.payload.payload.payload, NoPayload)
+
+
++ Test TLS CertificateStatus
+= Reading test session - CertificateStatus
+assert(isinstance(cert_stat, TLSCertificateStatus))
+assert(cert_stat.responselen == 471)
+cert_stat.response[0].responseStatus == 0
+# we leave the remaining OCSP tests to x509.uts
+
+
++ Test TLS ServerKeyExchange
+= Reading test session - ServerKeyExchange
+assert(isinstance(ske, TLSServerKeyExchange))
+p = ske.params
+assert(isinstance(p, ServerECDHNamedCurveParams))
+assert(p.named_curve == 0x0017)
+assert(p.point[0] == '\x04' and p.point[1:5] == '\xc3\x9d\x1cD' and p.point[-4:] == 'X\x19\x03u')
+assert(ske.sig.sig_alg == 0x0601)
+ske.sig.sig_val[:4] == 'y\x8aQ\x11' and ske.sig.sig_val[-4:] == '`15\xef'
+
+
++ Test TLS ServerHelloDone
+= Reading test session - ServerHelloDone
+assert(isinstance(shd, TLSServerHelloDone))
+shd.msglen == 0
+
++ Test tls_session
+= Reading test session - Context checks after 1st RTT
+t = shd.tls_session
+assert(len(t.handshake_messages) == 6)
+assert(t.handshake_messages_parsed[-1] is shd)
+assert(t.tls_version == 0x0303)
+assert(t.client_kx_ffdh_params is None)
+assert(t.client_kx_ecdh_params is not None)
+pn = t.server_kx_pubkey.public_numbers()
+x = pkcs_i2osp(pn.x, pn.curve.key_size/8)
+y = pkcs_i2osp(pn.y, pn.curve.key_size/8)
+assert(x[:4] == '\xc3\x9d\x1cD' and y[-4:] == 'X\x19\x03u')
+assert(t.rcs.row == "read")
+assert(t.wcs.row == "write")
+t.rcs.ciphersuite.val == 0
+
+
++ Test TLS
+= Reading test session - TLS parsing (with encryption) does not throw any error
+# XXX Something should be done, as for instance the reading of the 1st CCS
+# will mess up the reading state of the other side (even before the 2nd CCS).
+t5 = TLS(p5_cke_ccs_fin, tls_session=t1.tls_session)
+
+
++ Test TLS ClientKeyExchange
+= Reading test session - ClientKeyExchange
+cke = t5.msg[0]
+ccs = t5.payload.msg[0]
+rec_fin = t5.payload.payload
+fin = t5.payload.payload.msg[0]
+isinstance(t5.payload.payload.payload, NoPayload)
+assert(isinstance(cke, TLSClientKeyExchange))
+k = cke.exchkeys
+assert(isinstance(k, ClientECDiffieHellmanPublic))
+assert(k.ecdh_Yclen == 65)
+assert(k.ecdh_Yc[:4] == '\x04\xd2\x07\xce' and k.ecdh_Yc[-4:] == '\xdc\x86[\xe7')
+
+
++ Test TLS ChangeCipherSpec
+= Reading test session - ChangeCipherSpec
+assert(isinstance(ccs, TLSChangeCipherSpec))
+ccs.msgtype == 1
+
+
++ Test TLS Finished
+= Reading test session - Finished
+assert(rec_fin.version == 0x0303)
+assert(rec_fin.len == 16)
+assert(rec_fin.iv == '\x00\x00\x00\x00\x00\x00\x00\x00')
+assert(rec_fin.mac == '\xc7^\xc1\x8e\x81M\xff\x00\x0f}G\xf2\x8c\xab\n=')
+assert(not rec_fin.pad and not rec_fin.padlen)
+from scapy.layers.tls.record import _TLSEncryptedContent
+assert(isinstance(fin, _TLSEncryptedContent))
+fin.load == '\xd9\xcb,\x8cM\xfd\xbc9\xaa\x05\xf3\xd3\xf3Z\x8a-'
+
+
++ Test TLS Tick-CCS-Fin
+= Reading test session - Ticket, CCS & Finished
+t6 = TLS(p6_tick_ccs_fin)       # empty tls_session
+tick = t6.msg[0]
+assert(isinstance(tick, TLSNewSessionTicket))
+assert(tick.msgtype == 4)
+assert(tick.lifetime == 1200)
+assert(tick.ticketlen == 192)
+assert(tick.ticket[:4] == 'c\xccwJ' and tick.ticket[-4:] == '\xf3.\xcf\x04')
+ccs = t6.payload.msg[0]
+assert(isinstance(ccs, TLSChangeCipherSpec))
+rec_fin = TLS(str(t6.payload.payload), tls_session=t1.tls_session)
+assert(rec_fin.iv == '\xd8m\x92\t5YZ:')
+assert(rec_fin.mac == '\xecguD\xa8\x87$<7+\n\x94\x1e9\x96\xfa')
+assert(isinstance(rec_fin.msg[0], _TLSEncryptedContent))
+rec_fin.msg[0].load == '7\\)`\xaa`\x7ff\xcd\x10\xa9v\xa3*\x17\x1a'
+
+
++ Test TLS ApplicationData
+= Reading test session - ApplicationData
+t7 = TLS(p7_data, tls_session=t1.tls_session)
+assert(t7.iv == '\x00\x00\x00\x00\x00\x00\x00\x01')
+assert(t7.mac == '>\x1dLb5\x8e+\x01n\xcb\x19\xcc\x17Ey\xc8')
+assert(not t7.pad and not t7.padlen)
+assert(isinstance(t7.msg[0], _TLSEncryptedContent))
+len(t7.msg[0].load) == 478
+
+
+###############################################################################
+############################## Building packets ###############################
+###############################################################################
+
++ Test Build TLS empty records
+= Building packets - Various default records
+str(TLS())
+str(TLSClientHello())
+str(TLSServerHello())
+str(TLSCertificate())
+str(TLSServerKeyExchange())
+str(TLSClientKeyExchange())
+str(TLSAlert())
+str(TLSChangeCipherSpec())
+str(TLSApplicationData()) == ''
+
+
++ Test Build TLS ClientHello
+= Building packets - ClientHello with automatic length computation
+ch = TLSClientHello()
+ch.msgtype = 'client_hello'
+ch.version = 'TLS 1.2'
+ch.gmt_unix_time = 0x26ee2ddd
+ch.random_bytes = 'X\xe1\xb1T\xaa\xb1\x0b\xa0zlg\xf8\xd14]%\xa9\x91d\x08\xc7t\xcd6\xd4"\x9f\xcf'
+ch.ciphers = [TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_3DES_EDE_CBC_SHA]
+ch.comp = 'null'
+ext1 = TLS_Ext_ServerName(servernames=ServerName(servername='mn.scapy.wtv'))
+ext2 = TLS_Ext_RenegotiationInfo()
+ext3 = TLS_Ext_SupportedEllipticCurves(ecl=['secp256r1', 'secp384r1', 'secp521r1'])
+ext4 = TLS_Ext_SupportedPointFormat(ecpl='uncompressed')
+ext5 = TLS_Ext_SessionTicket()
+ext6 = TLS_Ext_NPN()
+ext7 = TLS_Ext_ALPN(protocols=[ProtocolName(protocol='h2-16'), ProtocolName(protocol='h2-15'), ProtocolName(protocol='h2-14'), ProtocolName(protocol='h2'), ProtocolName(protocol='spdy/3.1'), ProtocolName(protocol='http/1.1')])
+ext8 = TLS_Ext_CSR(stype='ocsp', req=OCSPStatusRequest())
+ext9 = TLS_Ext_SignatureAlgorithms(sig_algs=['sha256+rsa', 'sha384+rsa', 'sha512+rsa', 'sha1+rsa', 'sha256+ecdsa', 'sha384+ecdsa', 'sha512+ecdsa', 'sha1+ecdsa', 'sha256+dsa', 'sha1+dsa'])
+ch.ext = [ext1, ext2, ext3, ext4, ext5, ext6, ext7, ext8, ext9]
+t = TLS(type='handshake', version='TLS 1.0', msg=ch)
+str(t) == '\x16\x03\x01\x00\xc7\x01\x00\x00\xc3\x03\x03&\xee-\xddX\xe1\xb1T\xaa\xb1\x0b\xa0zlg\xf8\xd14]%\xa9\x91d\x08\xc7t\xcd6\xd4"\x9f\xcf\x00\x00\x16\xc0+\xc0/\xc0\n\xc0\t\xc0\x13\xc0\x14\x003\x009\x00/\x005\x00\n\x01\x00\x00\x84\x00\x00\x00\x11\x00\x0f\x00\x00\x0cmn.scapy.wtv\xff\x01\x00\x01\x00\x00\n\x00\x08\x00\x06\x00\x17\x00\x18\x00\x19\x00\x0b\x00\x02\x01\x00\x00#\x00\x003t\x00\x00\x00\x10\x00)\x00\'\x05h2-16\x05h2-15\x05h2-14\x02h2\x08spdy/3.1\x08http/1.1\x00\x05\x00\x05\x01\x00\x00\x00\x00\x00\r\x00\x16\x00\x14\x04\x01\x05\x01\x06\x01\x02\x01\x04\x03\x05\x03\x06\x03\x02\x03\x04\x02\x02\x02'
+
+
++ Test Build TLS ServerKeyExchange
+= Building packets - ServerHello context linking
+from scapy.layers.tls.crypto.kx_algs import KX_ECDHE_RSA
+from scapy.layers.tls.crypto.cipher_block import Cipher_AES_256_CBC
+sh = TLSServerHello(gmt_unix_time=0x41414141, random_bytes='B'*28, cipher='TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA')
+t = TLS(msg=sh)
+str(t)
+assert(isinstance(t.tls_session.pwcs.ciphersuite, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA))
+assert(isinstance(t.tls_session.pwcs.key_exchange, KX_ECDHE_RSA))
+assert(isinstance(t.tls_session.pwcs.cipher, Cipher_AES_256_CBC))
+assert(isinstance(t.tls_session.pwcs.hmac, Hmac_SHA))
+t.tls_session.server_random == 'A'*4+'B'*28
+
+
++ Test Build TLS wrong record
+= Building packets - ChangeCipherSpec with forged, forbidden field values
+t = TLS(msg=TLSChangeCipherSpec())
+assert(str(t) == '\x14\x03\x03\x00\x01\x01')
+t.len = 0
+assert(str(t) == '\x14\x03\x03\x00\x00\x01')
+t.type = 0xde
+t.version = 0xadbe
+t.len = 0xefff
+str(t) == '\xde\xad\xbe\xef\xff\x01'
+
+
+###############################################################################
+############################ Automaton behaviour ##############################
+###############################################################################
+
+# see test/run_openssl_tests
+
+
diff --git a/test/tls/__init__.py b/test/tls/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..1b5e2a931c9dd57492caac736d151419500654d4
--- /dev/null
+++ b/test/tls/__init__.py
@@ -0,0 +1,8 @@
+## This file is part of Scapy
+## Copyright (C) 2016 Maxence Tury <maxence.tury@ssi.gouv.fr>
+## This program is published under a GPLv2 license
+
+"""
+Examples and test PKI for the TLS module.
+"""
+
diff --git a/test/tls/example_client.py b/test/tls/example_client.py
new file mode 100755
index 0000000000000000000000000000000000000000..3c5f9794c6b5f7183061e150d1e8725f1a3a165f
--- /dev/null
+++ b/test/tls/example_client.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+## This file is part of Scapy
+## This program is published under a GPLv2 license
+
+"""
+Basic TLS client. A ciphersuite may be commanded via a first argument.
+
+For instance, "sudo ./client_simple.py c014" will try to connect to any TLS
+server at 127.0.0.1:4433, with suite TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA.
+"""
+
+import os
+import sys
+
+basedir = os.path.abspath(os.path.join(os.path.dirname(__file__),"../../"))
+sys.path=[basedir]+sys.path
+
+from scapy.layers.tls.automaton import TLSClientAutomaton
+from scapy.layers.tls.handshake import TLSClientHello
+
+
+if len(sys.argv) == 2:
+    ch = TLSClientHello(ciphers=int(sys.argv[1], 16))
+else:
+    ch = None
+
+t = TLSClientAutomaton(client_hello=ch)
+t.run()
+
+
diff --git a/test/tls/example_server.py b/test/tls/example_server.py
new file mode 100755
index 0000000000000000000000000000000000000000..7d4d9664c1ba49386032cca6e47f1a1a6c38cfae
--- /dev/null
+++ b/test/tls/example_server.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+## This file is part of Scapy
+## This program is published under a GPLv2 license
+
+"""
+Basic TLS server. A preferred ciphersuite may be provided as first argument.
+
+For instance, "sudo ./server_simple.py c014" will start a server accepting
+any TLS client connection. If provided, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+will be preferred to any other suite the client might propose.
+"""
+
+import os
+import sys
+
+basedir = os.path.abspath(os.path.join(os.path.dirname(__file__),"../../"))
+sys.path=[basedir]+sys.path
+
+from scapy.layers.tls.automaton import TLSServerAutomaton
+
+
+if len(sys.argv) == 2:
+    pcs = int(sys.argv[1], 16)
+else:
+    pcs = None
+
+t = TLSServerAutomaton(mycert=basedir+'/test/tls/pki/srv_cert.pem',
+                       mykey=basedir+'/test/tls/pki/srv_key.pem',
+                       preferred_ciphersuite=pcs)
+t.run()
+
+
diff --git a/test/tls/pki/ca_cert.pem b/test/tls/pki/ca_cert.pem
new file mode 100644
index 0000000000000000000000000000000000000000..25b4c52bfbfd9f307ed00668a30c4601d4aa54a7
--- /dev/null
+++ b/test/tls/pki/ca_cert.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDiDCCAnCgAwIBAgIJALpa+1bjqpmeMA0GCSqGSIb3DQEBCwUAMFQxCzAJBgNV
+BAYTAk1OMRQwEgYDVQQHDAtVbGFhbmJhYXRhcjEXMBUGA1UECwwOU2NhcHkgVGVz
+dCBQS0kxFjAUBgNVBAMMDVNjYXB5IFRlc3QgQ0EwHhcNMTYwOTE2MTAyNjQ1WhcN
+MjYwOTE2MTAyNjQ1WjBUMQswCQYDVQQGEwJNTjEUMBIGA1UEBwwLVWxhYW5iYWF0
+YXIxFzAVBgNVBAsMDlNjYXB5IFRlc3QgUEtJMRYwFAYDVQQDDA1TY2FweSBUZXN0
+IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Gy5LahBQAwiGUrP
+ZLrBUIEZAlnsOkCd7Al+wJwaPFhMLy+nga0ubMuUBo4P9DQv729jpiRnu6Q1ScO3
+PcRX5FNdEKxV9fLOWUJp5MIMz5k6snJ5+kEMouNXj/umUN+qHHyvgbDVEw7RroTN
+mLqnWs2Al5Rd0NAxp4lLoYdVUclXrlOGY7Ldkq4WAgdlJZQ6PiZyeoz6YNeoRNmR
+h4RGKDmzoSEKqsAUlozEg3seC1EbU0TtY9r3O09tEGegQUARIxXV3qpWjFxakax+
+XzzldwuoIWMO7x8RqH9X3Y+ktcLOxiPhKmGqcR3kNyMcARatdIjdV0b3jAeH68of
+DVxXoQIDAQABo10wWzAdBgNVHQ4EFgQUZlOU9BXRvWdosFE3MjXhpKreB3wwHwYD
+VR0jBBgwFoAUZlOU9BXRvWdosFE3MjXhpKreB3wwDAYDVR0TBAUwAwEB/zALBgNV
+HQ8EBAMCAgQwDQYJKoZIhvcNAQELBQADggEBAJNnhilPvSXjGFSUNp5XG81i44lI
+wqsYcWl7cuNjFS8tqciMb1Q8Lr768+CPFYlf3OjwX43SCe621oKtRZV0O3bizSZd
+5xuCAEsCe1jkk4d7Nxk13/AB2z6YKvWeud/vLAQpYIwzV/qExAOv+ZLAj46t6S/E
+h/A/kNEXqBE5e+yysTUVNz+moI7P8Sw91yXuiPMSWJ4rla+nmfFWaKTP9vjEmEHt
+a+LA8VUiR2dEeLcRnVCgVJc0+AS6EjG662AKyNYP4AcmUaFvBKRiJpEgZwNmmOen
+PjNAbNxzEk7bJMG8GUmwYJ9cYznBFBOzAJNyMkG8wSmMYN3NgdnD4KYHYVE=
+-----END CERTIFICATE-----
diff --git a/test/tls/pki/ca_key.pem b/test/tls/pki/ca_key.pem
new file mode 100644
index 0000000000000000000000000000000000000000..fead823a80a3b737292d5f991bfbd22349ad4c1f
--- /dev/null
+++ b/test/tls/pki/ca_key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDQbLktqEFADCIZ
+Ss9kusFQgRkCWew6QJ3sCX7AnBo8WEwvL6eBrS5sy5QGjg/0NC/vb2OmJGe7pDVJ
+w7c9xFfkU10QrFX18s5ZQmnkwgzPmTqycnn6QQyi41eP+6ZQ36ocfK+BsNUTDtGu
+hM2YuqdazYCXlF3Q0DGniUuhh1VRyVeuU4Zjst2SrhYCB2UllDo+JnJ6jPpg16hE
+2ZGHhEYoObOhIQqqwBSWjMSDex4LURtTRO1j2vc7T20QZ6BBQBEjFdXeqlaMXFqR
+rH5fPOV3C6ghYw7vHxGof1fdj6S1ws7GI+EqYapxHeQ3IxwBFq10iN1XRveMB4fr
+yh8NXFehAgMBAAECggEAXSPpEO0604tYhaL30VTf5MD8Ux+qQFH2ALAxk5Nu6f6v
+dPq/yWSB9Z54NQGxQXk83qwRhQKJ1MHKCn/K2HBwsplKYpQRCgsKibrzJYZOQUuB
+fpNHzTzaj8Q2siJMLaH2HCrgJ33FinG55Fp2okTvWtWxHIvx7MnNFsh1IuceiqA3
+5tVSR7+kMraJgJ9auRNRQbH273LzntVOzAt339Xd38izsQ7CvYERAQGabTwo6BEC
+nDFfhWXPaxRt5JcJWcJNYSxYKigMmDh4oGXSb+mZeuojcXYcaHzyAToAjZ6x2hXU
+Vjxo7JMK+gvhJvlOpY2tjMNIkRh1P7gLrBSP8XcxjQKBgQDtSIr8qooaswEQ9H8W
+Tkr5ciLU4u6Wfhp26+M6oHPv57bbJI7qN68Z3l+cbtLxSqj0bcop1V+xvQjWOD+/
+ckNPm4aEmoIMP3a0oQARtJeR9uaos64uudc+1gpz9g7w+sO+khy9yAFdY1+9gsEi
+WqqbtVQ2e3RABoolr14Pcc222wKBgQDg3XAjcXupfsrDhQP5R45kY/eVFWUk7PMB
+jpPl6+ZfoB/vqUuCZBX3UYrFDe4O+n0R6oF9ACXLRsVuaG/IZYDFczsBvEr8WpOG
+78lpTbgUwudKlnzSBl01aUZu7zpJ3oFhX1DgZspr72UfHl9+/NwezV4gFd0ZKGLO
+s/aLsh3eMwKBgDm3TH9a6A7IfbjnD8aYMqpsNca8kDYw5DUK+ZF4F9tB7HtvcAfO
+lZvgODdvyYWBmIkj72mvigBMr8qTkgX6QB8sAFNe1cUu5qvXAZJM8BVEDiT416Rr
+9cxF+fLs5gN9q4E+Pxl2fcZ+dno9RMcbcKZBPAOokcVFEfNKrcFp+BTDAoGBAL42
+0ztILgFs/fxysq/V9f+6CJ8WIB8iSVXR1A40hQXzH9DN9s/v9hzl32tdozkMb2wO
+YUbqLw5LaYtB0P1Fz643EX0gWJYr0IvenxPy6Hq3fIu9zQyk0Yfy69+/giEmlW9W
+/8UzbpvrQDEYslNrdpCfzLV7iTJU1XBhD3eQTm+9AoGAf1EX07Jk7357Y7+l/vB4
+Cd0g+k4yRadDM7tCrdYnZcdwhFoKtCC9y/ChBgHRkayMizJRYC218ou9muP3qYLD
+Wd+Sqtxg7LlDRa+m8db0SI40a0AMb0fGKXzy4AxD1EJrBLt8rdaDrqoGF/Vwadjh
+sxUMjCPGDmiV+ucqbJR9/NE=
+-----END PRIVATE KEY-----
diff --git a/test/tls/pki/cli_cert.pem b/test/tls/pki/cli_cert.pem
new file mode 100644
index 0000000000000000000000000000000000000000..66f48c2bf01c2d58ebe15ffb65d07dfc9c1da1b7
--- /dev/null
+++ b/test/tls/pki/cli_cert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDnjCCAoagAwIBAgIJAP4EVw3HJ+n4MA0GCSqGSIb3DQEBCwUAMFQxCzAJBgNV
+BAYTAk1OMRQwEgYDVQQHDAtVbGFhbmJhYXRhcjEXMBUGA1UECwwOU2NhcHkgVGVz
+dCBQS0kxFjAUBgNVBAMMDVNjYXB5IFRlc3QgQ0EwHhcNMTYwOTE2MTAzMDUyWhcN
+MjYwOTE1MTAzMDUyWjBYMQswCQYDVQQGEwJNTjEUMBIGA1UEBwwLVWxhYW5iYWF0
+YXIxFzAVBgNVBAsMDlNjYXB5IFRlc3QgUEtJMRowGAYDVQQDDBFTY2FweSBUZXN0
+IENsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMMJN5ioDSgj
+OufUeWJI7Ali5QPySoD8neeSXkzGlm48SGDNzoKQs0v75gmlOs/mditKsPfu9HQA
+Ohd97oor8HQLhEMqF6OpiGyjOo7i3+/X8bPhJJsn6pYmJ5PH8HjduHuGFGt9Or2t
+wpQCd1t5ZN3KSZpnEk9K3HS3GJHHsO69UvuIWsksjjetAtD7HpvdeMGrMRmTEgI3
+EFVUigfP1y8uaoq648TPG31MFx8cpxfKhNtstmRPZNpyl2NpzoZQFXskbMO8pVYc
+QxTwA6/AgDBYoaYRdV4hq5MSfcGloy5OIsR/8toamJ0EjbypulnC0+F78goP/Puw
+isuHi2YYJxUCAwEAAaNvMG0wCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwHQYDVR0O
+BBYEFAPVvKSOtt3Hj63JN8ZtzEGSZZ5IMB8GA1UdIwQYMBaAFGZTlPQV0b1naLBR
+NzI14aSq3gd8MBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IB
+AQAhzb8LBydZ+ulSyIiF4/PgTh7/sQOC1LroP0GhVsOLNZ07qvw8teXJO9HwsAqm
+14GeLJh5XWhoL4tkq9RMcwuZL2vuVl9FB9inLerA1FU/ErJJOIIC3drIORTTQ2ot
+lUkbKOAQFzZfP0d+iuCFi0r0Kcu7BAZETTeG4cAoIoIIhh2AZ8DfT3E6xP7OKUMA
+3m1gA4M1hwiAhFvj4iBaG20Sb0RXpDuTToHEfCEnuQdoex3F8gmn88yt22FNakqe
+cr9ooif+id4ErdKLozgG1i0PFYCFRj2/fUPTQw3BSgfo+XNcAjA04CowuhPAjsL8
+ybC+9OE5YPSxfOqOPB4sK/w2
+-----END CERTIFICATE-----
diff --git a/test/tls/pki/cli_key.pem b/test/tls/pki/cli_key.pem
new file mode 100644
index 0000000000000000000000000000000000000000..3092d55bffe2cb63df6ed5c9dc11f8bdc761101c
--- /dev/null
+++ b/test/tls/pki/cli_key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDDCTeYqA0oIzrn
+1HliSOwJYuUD8kqA/J3nkl5MxpZuPEhgzc6CkLNL++YJpTrP5nYrSrD37vR0ADoX
+fe6KK/B0C4RDKhejqYhsozqO4t/v1/Gz4SSbJ+qWJieTx/B43bh7hhRrfTq9rcKU
+AndbeWTdykmaZxJPStx0txiRx7DuvVL7iFrJLI43rQLQ+x6b3XjBqzEZkxICNxBV
+VIoHz9cvLmqKuuPEzxt9TBcfHKcXyoTbbLZkT2Tacpdjac6GUBV7JGzDvKVWHEMU
+8AOvwIAwWKGmEXVeIauTEn3BpaMuTiLEf/LaGpidBI28qbpZwtPhe/IKD/z7sIrL
+h4tmGCcVAgMBAAECggEBAJU951ocNj0hgEDH+L55uIySLVawv8wmAhqiiSBM0e22
+mVfiBIUqftjE/8kfs3pFCuWjuPlv04U0az9wsOjwKIZUDbhrbD1jTC59VSDjgKKC
+ZsTTonRLvhl5Rs2xsFR8rV9wQQ3jfOCKJxulK3pG0SVaVqoc9wjP6xQwy086NCzq
+QLnM2BESEED9cfbO7zVE7bJzLmAH9v4eF5hpuQ3SQZGE6oib0uPPnAyl5iOZZHnu
+4DTxVHYIYKCegL47VpeL3h80Yzu8bAuqoSsLxbBcAoYB9e9ZMVi8o1NaVM9eT0/m
+HSb+rkN39YrrtXDkXxqmwsh8B7R9gRBxMFIzsI83XN0CgYEA+KSoQ3zpEjjFioB+
+006JcATCslLERgDuuaVqVlnt5a983i/3nwvICxfsGrFaQJ4TkhXEYuZro4Zovdc1
+9IAj8DEQRNh7H7mZoWtQnFC32VOdAUVZVpopL6009xKs/II9pRKg4Vm6mpb47xfl
+Yk/upy5yV4gHThkMLccJ8PqmIosCgYEAyM6Da1vflkzoKMu7HmJNmi59hnk5N15V
+C8BcYNaodiHucrcyzOexaVnIQJ7+CgVen+RF9wwcIQxUsw8Vcs0AZ4ipLDOFZXNk
+k0oGjr5oeCIHJvA9W1BSXmcJ5Beo4ASr0GmIQpfsFohFuHXn7ezQWqA6Me8HwFGF
+l8goN3VyMN8CgYBJ5u7YOE0yDEuykeSgO6yf7dpMlEsgH3DVHvRPPCV4akNr6sfn
+ruHDYlXbzTDtGc7pUazwVFpT3UROgKPZyyhjYMHcJJfb4xdlofbwrxEl+DMnSIx4
+MBPjxtCCSzu9RZy67qGAuWG8RvkwX2LfaLCfYi+8EoNRVCKJjKpIxMcSZwKBgC9E
+xZTJDKmxstiflI2DcGcB2JSGBpzs/LIGdvhor0EXnaytSS0IwS9ebhAgHQa42txi
+fMG5vQlegLWhsFfUv+qfNcts2VLXRe6R91c0pRzaTbqxxI+xKaKFOMPTefI5x0QJ
+A4VBg9aN/3N7dbwBCc67dtd4P+faiMsA186uO9IbAoGAVvh9bC5zoCfenexRe9si
+c/baEsOlPjMnM/QKz6Ue/65YTzpJYQ1hVlGqP2DsN28f5yJetHLcUINaPxlegKdL
+Ifhmdg5HO7v35NHVghXq+/M8xYRzKD6nqRqB8wEdGb+XOo5QHXsLp3wBQ7QXL4UI
+mrJFWi1wtyQOdIO4GJC8Bc0=
+-----END PRIVATE KEY-----
diff --git a/test/tls/pki/srv_cert.pem b/test/tls/pki/srv_cert.pem
new file mode 100644
index 0000000000000000000000000000000000000000..e559f326c9002c52b00263b16acc4bafb72dd194
--- /dev/null
+++ b/test/tls/pki/srv_cert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDnjCCAoagAwIBAgIJAP4EVw3HJ+n2MA0GCSqGSIb3DQEBCwUAMFQxCzAJBgNV
+BAYTAk1OMRQwEgYDVQQHDAtVbGFhbmJhYXRhcjEXMBUGA1UECwwOU2NhcHkgVGVz
+dCBQS0kxFjAUBgNVBAMMDVNjYXB5IFRlc3QgQ0EwHhcNMTYwOTE2MTAyODExWhcN
+MjYwOTE1MTAyODExWjBYMQswCQYDVQQGEwJNTjEUMBIGA1UEBwwLVWxhYW5iYWF0
+YXIxFzAVBgNVBAsMDlNjYXB5IFRlc3QgUEtJMRowGAYDVQQDDBFTY2FweSBUZXN0
+IFNlcnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMzx8ZtgLWCu
+8pgNJynZwAlZTA9KMKhS3+WxIZ9Pwz1Wk91fxvez9lWL55Li3vKFSbShLPT9dqhn
+ygQgYBEYpvKptqYd2arl2duv5q9VV5//Uoll5oBigCGUvM+BG8tnwp21BXcEpseI
+GIB4aJU23pcbtmGHQhp1mEWC6z4yEcibhkI5jU0St1gbGfOdK6GYgsrXOyT7CTmw
+vMKVz4IpdRYpP0IgFytNQIxWbK26DzSFsX9AeXF4t6UEu5T3tUGV7nzrjQx5aFnv
+y7P6Pnge7mdMet3gme/a5++yCV2+gCAhBYMsRNtdKnYppbAjiHQHVCLWKXqS9W8t
+nuf4JiucWGUCAwEAAaNvMG0wCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwHQYDVR0O
+BBYEFKErIHDSa4DlZbzrAw+In3St3fYTMB8GA1UdIwQYMBaAFGZTlPQV0b1naLBR
+NzI14aSq3gd8MBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4IB
+AQCBiJJza5PnldbdQe6OHr2jSFinQTU/e33QN5gOuCyUd8hRNkCtWQkoyFbW6lus
+tNg/aLdmyuFWN6kAZepRyeyyaUld+ePA7WFUyRKfxrAKc1XoVTVg7xw28NrRkHdW
+BLirOO73CcWlmJAj6h/bFX8yKIGrm4UCS5XnN1F7G0gu+z5Sow20RqmSOhwf1woe
+WEr6LlGPKcYeuA4xDnPxJ4gXyshpDPqDzbN5DhSwuJsvOi0J4/wG8Dpu/TY7KxoJ
+KuirX4xA5IGyvPeDZxFuTpPqIq//o5p3V3bQCzis+IqUNY7X1GHMAf8ktI9hI7qI
+11nk6boqTrUVD5zQ6gaR2d6r
+-----END CERTIFICATE-----
diff --git a/test/tls/pki/srv_key.pem b/test/tls/pki/srv_key.pem
new file mode 100644
index 0000000000000000000000000000000000000000..62248e3e46310d661e486f585d706630308f7df1
--- /dev/null
+++ b/test/tls/pki/srv_key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDM8fGbYC1grvKY
+DScp2cAJWUwPSjCoUt/lsSGfT8M9VpPdX8b3s/ZVi+eS4t7yhUm0oSz0/XaoZ8oE
+IGARGKbyqbamHdmq5dnbr+avVVef/1KJZeaAYoAhlLzPgRvLZ8KdtQV3BKbHiBiA
+eGiVNt6XG7Zhh0IadZhFgus+MhHIm4ZCOY1NErdYGxnznSuhmILK1zsk+wk5sLzC
+lc+CKXUWKT9CIBcrTUCMVmytug80hbF/QHlxeLelBLuU97VBle58640MeWhZ78uz
++j54Hu5nTHrd4Jnv2ufvsgldvoAgIQWDLETbXSp2KaWwI4h0B1Qi1il6kvVvLZ7n
++CYrnFhlAgMBAAECggEAIPA9uZAimuhjOwbaJYLGt3nvnIF7AoKXU449biJeqawR
+hcHP852r2KHsrRHjbSz45JwG4rUd7gEIWdNuPTEuG9Ak99vSUQIyGnnR5JodxCw/
+8q869aVfHIaQNfV1JyLdB4XBhBhuSaFY9sTjYh/4dGbS0Cfx+titiXZ6InvfmdMD
+eLd/ZO35/BwtWN3J2ntRziTTREKLeEYFEe7FtXKGwDGIsvVn7egckefKMnflhMFA
+SuoPn2VvTqmhiwSuATdx1TP4XOVdVzuL2wT7brS7qHvabRDBKdVOfrNGOoMdnnua
+ursIQjQindNT8kVK8EGxws9eFr/dooYYFR72IusTfQKBgQDuQBzzKEtt86uRCbZX
+Y3lu0MJnR5OOodfGBBYF9Ue+W3OJTd9EvXLSgLBLvwirB7lsNXgXf8LHCTQOtF3H
+lnB8jE5OFSDGeSKWmUwZS+KVzq8vy7Qylp9i6x4pElwGUeba6AqeZZ+jUUn/HzdB
+s2pO8YWqyOp/Zo/m8P+vPZN4fwKBgQDcNqJ4Dutt/i60E9kaktGQVQODRNMhYCEq
+E5fhwJiZ0E9FBeuKPKjo7dGIux3KPQPBv3T0zjmB+M5QERVe5/ID8iytgbHGlnsg
+916iTN9rvi1Gk518vyFPsYjX9pPiQIayRBQKOXSYIkY+6rj2384XPRlZrN8D9n3Q
++An1JXfdGwKBgDs3YjqpnD3i35S4BkMoLUl2x6rl5m4AGeJUp6ipc0CD+G57FXA/
+aieZ5rec7qmbzOFxVLz6e03/Ipo5CEoQQTsjoF7V74SFHSyzQ2/SJao4aeCGT+52
+83yhlah9sLO9bZShMep2tbvg+3RWrOQ+lMC0VRXCxE4QDtpGsjY7Jsk/AoGAPstV
+iOa4O6U/rBn8zpcPKxkS51u42MuQqW7s4HMLENFVyVjm0YR6pfEqztKMrB6584Wk
+1Cn6PBW2vx4f+fAqEvX7x340M2y1r7DaS22gSBjy0C1Hu0rFNPRrESo/AUVlI3BG
+RqQbm0YqwcYs+DjZi8bgc7HX5kljlzMjo8QLagECgYA1DHAWv4WVrHt4I8V4ZCth
+9DZEtEOFpYjuoFh/xSIMZLsnvWRuyYVWcQwAqmK0Ew4m5opHFsQzABeGLVsK5aHX
+zmbYiRUuZGVpyc7c5XXomw50X8ajfQ+P21OPPc33h96cdHi2qbJIejZPia6A6ThU
+u13D93hAM6bzH6Ds5FPUQw==
+-----END PRIVATE KEY-----
diff --git a/test/tls/run_tests_tls_netaccess b/test/tls/run_tests_tls_netaccess
new file mode 100755
index 0000000000000000000000000000000000000000..0d6a87d24b7c744c578ea901cf0d4901f8f3702a
--- /dev/null
+++ b/test/tls/run_tests_tls_netaccess
@@ -0,0 +1,103 @@
+#!/bin/bash
+
+
+function test_tls_server {
+  msg=$1
+  suite=$2
+  version=$3
+  EXIT_CODE=test_tls_server_tmp_code
+  OSSL_STDO=test_tls_server_tmp_openssl_stdout
+  OSSL_STDE=test_tls_server_tmp_openssl_stderr
+  SCAPY_STDE=test_tls_server_tmp_scapy_stderr
+
+  echo "1" > $EXIT_CODE
+  ($TRAVIS_SUDO python travis_test_server.py "$msg" 2>$SCAPY_STDE; echo $? > $EXIT_CODE) &
+  sleep 2         # wait for the server to start
+
+  echo -n "$msg" | sudo openssl s_client -cipher $suite $version 1>$OSSL_STDO 2>$OSSL_STDE
+  sleep 0.5       # wait for the connection to be established, then torn down
+
+  if [[ -z $version ]];
+  then
+    version=""
+  else
+    version="and option $version"
+  fi
+
+  if [ $(<$EXIT_CODE) == "0" ];
+  then
+    echo "PASSED - TLS server test with cipher suite $suite $version"
+    rm -f $EXIT_CODE $OSSL_STDO $OSSL_STDE $SCAPY_STDE
+  else
+    echo "FAILED - TLS server test with cipher suite $suite $version"
+    echo -e "\n###\nHere are scapy writings to stderr:\n"
+    cat $SCAPY_STDE
+    echo -e "\nHere are openssl writings to stdout & stderr:\n"
+    cat $OSSL_STDO
+    cat $OSSL_STDE
+    echo -e "\n###\n"
+    rm -f $EXIT_CODE $OSSL_STDO $OSSL_STDE $SCAPY_STDE
+    exit 1
+  fi
+}
+
+
+function test_tls_client {
+  # we test our TLS client against our own TLS server, because s_server scripting is broken
+  # be careful, as this might not detect every error (e.g. if key derivation was
+  # identically non-standard on both sides, this would not be detected)
+  msg=$1
+  suite=$2
+  version=$3
+  EXIT_CODE=test_tls_client_tmp_code
+  SRV_STDO=test_tls_client_tmp_server_stdout
+  SRV_STDE=test_tls_client_tmp_server_stderr
+  CLI_STDO=test_tls_client_tmp_client_stdout
+  CLI_STDE=test_tls_client_tmp_client_stderr
+
+  ($TRAVIS_SUDO python travis_test_server.py "$msg" 1>$SRV_STDO 2>$SRV_STDE; echo $? > $EXIT_CODE) &
+  sleep 1         # wait for the server to start
+
+  $TRAVIS_SUDO python travis_test_client.py "$msg" $suite $version 1>$CLI_STDO 2>$CLI_STDE
+  sleep 0.5
+
+  if [[ -z $version ]];
+  then
+    version=""
+  else
+    version="and version $version"
+  fi
+
+  if [ $(<$EXIT_CODE) == "0" ];
+  then
+    echo "PASSED - TLS client test with cipher suite $suite $version"
+    rm -f $CLI_STDO $CLI_STDE $SRV_STDO $SRV_STDE $EXIT_CODE
+  else
+    echo "FAILED - TLS client test with cipher suite $suite $version"
+    echo -e "\n###\nHere are scapy client writings to stdout & stderr:\n"
+    cat $CLI_STDO
+    cat $CLI_STDE
+    echo -e "\nHere are scapy server writings to stdout & stderr:\n"
+    cat $SRV_STDO
+    cat $SRV_STDE
+    echo -e "\n###\n"
+    rm -f $CLI_STDO $CLI_STDE $SRV_STDO $SRV_STDE $EXIT_CODE
+    exit 1
+  fi
+}
+
+
+echo "TLS server automaton tests"
+test_tls_server "Testing TLS server with TLS 1.0 and TLS_RSA_WITH_RC4_128_SHA" "RC4-SHA" "-tls1"
+test_tls_server "Testing TLS server with TLS 1.2 and TLS_DHE_RSA_WITH_AES_128_CBC_SHA256" "DHE-RSA-AES128-SHA256" "-tls1_2"
+test_tls_server "Testing TLS server with TLS 1.2 and TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" "ECDHE-RSA-AES256-GCM-SHA384" "-tls1_2"
+echo
+sleep 1
+
+echo "TLS client automaton tests"
+test_tls_client "Testing TLS client with TLS 1.0 and TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA" "0088" "0301"
+test_tls_client "Testing TLS client with TLS 1.1 and TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" "c013" "0302"
+test_tls_client "Testing TLS server with TLS 1.2 and TLS_DHE_RSA_WITH_AES_128_GCM_SHA256" "009e" "0303"
+test_tls_client "Testing TLS server with SSLv3 and TLS_RSA_EXPORT_WITH_RC4_40_MD5" "0003" "0300"
+
+
diff --git a/test/tls/travis_test_client.py b/test/tls/travis_test_client.py
new file mode 100755
index 0000000000000000000000000000000000000000..7bbdeb9b3404f0f940667112cbe86a6cc95a708a
--- /dev/null
+++ b/test/tls/travis_test_client.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+## This file is part of Scapy
+## This program is published under a GPLv2 license
+
+"""
+TLS client used in unit tests.
+Usage: [sudo] ./unit_test_client.py [send_data [cipher_suite_code [version]]]
+
+Start our TLS client, send our send_data, and terminate session with an Alert.
+Optional cipher_cuite_code and version may be provided as hexadecimal strings
+(e.g. c09e for TLS_DHE_RSA_WITH_AES_128_CCM and 0303 for TLS 1.2).
+Reception of the exact send_data on the server is to be checked externally.
+"""
+
+import os
+import sys
+
+basedir = os.path.abspath(os.path.join(os.path.dirname(__file__),"../../"))
+sys.path=[basedir]+sys.path
+
+from scapy.layers.tls.automaton import TLSClientAutomaton
+from scapy.layers.tls.handshake import TLSClientHello
+
+
+send_data = cipher_suite_code = version = None
+
+if len(sys.argv) >= 2:
+    send_data = sys.argv[1]
+
+if len(sys.argv) >= 3:
+    cipher_suite_code = int(sys.argv[2], 16)
+
+if len(sys.argv) >= 4:
+    version = int(sys.argv[3], 16)
+
+
+ch = TLSClientHello(version=version, ciphers=cipher_suite_code)
+t = TLSClientAutomaton(client_hello=ch, data=send_data)
+t.run()
+
+
diff --git a/test/tls/travis_test_server.py b/test/tls/travis_test_server.py
new file mode 100755
index 0000000000000000000000000000000000000000..e262c63ecb1e6d263c7e1af878c5bca02824b2db
--- /dev/null
+++ b/test/tls/travis_test_server.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+
+## This file is part of Scapy
+## This program is published under a GPLv2 license
+
+"""
+TLS server used in unit tests.
+Usage: [sudo] ./unit_test_server.py [expected_data]
+
+When some expected_data is provided, a TLS client (e.g. openssl s_client)
+should send some application data after the handshake. If this data matches our
+expected_data, then we leave with exit code 0. Else we leave with exit code 1.
+If no expected_data was provided and the handshake was ok, we exit with 0.
+"""
+
+import os
+import sys
+from contextlib import contextmanager
+from StringIO import StringIO
+
+basedir = os.path.abspath(os.path.join(os.path.dirname(__file__),"../../"))
+sys.path=[basedir]+sys.path
+
+from scapy.layers.tls.automaton import TLSServerAutomaton
+
+
+@contextmanager
+def captured_output():
+    new_out, new_err = StringIO(), StringIO()
+    old_out, old_err = sys.stdout, sys.stderr
+    try:
+        sys.stdout, sys.stderr = new_out, new_err
+        yield sys.stdout, sys.stderr
+    finally:
+        sys.stdout, sys.stderr = old_out, old_err
+
+def check_output_for_data(out, err, data):
+    if err.getvalue():
+        sys.exit(1)
+
+    output = out.getvalue().strip()
+    if expected_data:
+        lines = output.split("\n")
+        for l in lines:
+            if l.startswith("Received"):
+                break
+        if l == ("Received '%s'" % data):
+            sys.exit(0)
+        sys.exit(1)
+    sys.exit(0)
+
+
+if len(sys.argv) == 2:
+    expected_data = sys.argv[1]
+else:
+    expected_data = None
+
+with captured_output() as (out, err):
+    t = TLSServerAutomaton(mycert=basedir+'/test/tls/pki/srv_cert.pem',
+                           mykey=basedir+'/test/tls/pki/srv_key.pem')
+    t.run()
+
+check_output_for_data(out, err, expected_data)
+
diff --git a/test/x509.uts b/test/x509.uts
index d61e2445dd239b0a6b473c70bb4a03c45ccd688e..e481e0ea06bc2eb355691d642d52ef6bad01da22 100644
--- a/test/x509.uts
+++ b/test/x509.uts
@@ -204,3 +204,45 @@ r = ASN1F_PACKET("otherName", None, X509_OtherName).randval()
 assert(isinstance(r, X509_OtherName))
 str(r.type_id) == '171.184.10.271'
 
+
+############ OCSP class ###############################################
+
+= OCSP class : OCSP Response import
+s = '0\x82\x01\xd3\n\x01\x00\xa0\x82\x01\xcc0\x82\x01\xc8\x06\t+\x06\x01\x05\x05\x070\x01\x01\x04\x82\x01\xb90\x82\x01\xb50\x81\x9e\xa2\x16\x04\x14Qh\xff\x90\xaf\x02\x07u<\xcc\xd9edb\xa2\x12\xb8Yr;\x18\x0f20160914121000Z0s0q0I0\t\x06\x05+\x0e\x03\x02\x1a\x05\x00\x04\x14\xcf&\xf5\x18\xfa\xc9~\x8f\x8c\xb3B\xe0\x1c/j\x10\x9e\x8e_\n\x04\x14Qh\xff\x90\xaf\x02\x07u<\xcc\xd9edb\xa2\x12\xb8Yr;\x02\x10\x07z]\xc36#\x01\xf9\x89\xfeT\xf7\xf8o>d\x80\x00\x18\x0f20160914121000Z\xa0\x11\x18\x0f20160921112500Z0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00\x90\xef\xf9\x15U\x88\xac@l\xf6n\x04C/\x1a\xf5\xbc[Xi\xd9U\xbe\'\xd3\xb7\xf5\xbb\t\xd8\xb1Tw\x9c2\xac\x7f\x88\xba\x98\xe4\xa13\xf4\xdc\xea\xf3\xacX\xe4,E\xf5\xa9\xc3\xf4B-N\xe0\x89D[\xbe\n\xc2h\x9ar\xfd\'.\xc8,\xed\x83\xc2\xf0\x89_\x8c\xc3\xe7\x8a\xad\xa4\x14\x03\x96\x02\xc4\xa8\xc8\x90\x96%X\x80\x95\x02\x9d_\xc82;m\xe9\x15\x00\xa8\x00\xb9\x01\xe3aN&\xe4\xd5\x8a\xc4w7\x0b\xc3~\xc5\xb1M\x10~T\x9e\x1d\xf6\x06\xf8\x12sTg\x14b_\xe7\xc04\xb4\xa3\xd2\x8f\xe6\xa6\xc4\x01q\x03j\xc8\xd4\xc7\x89\xdde\x99\x1a\xd9\x02\xe7\x17\xd1\xf40P\xef\xf6$\xee\xfad\xf4\xeb\xc8\xf7\x0bRL\x8b\xa5x\xe4R2\xe9\xc2\xfcB\nh\x93\xf7\x0ep4h\xeb\x17\x83\xc8\x88!\xc3W\x94WG\xfe3\x15C0qE&A\x99\xa8}\x1a\xda"\xa9O\xba\x90W_W\xado\x1c\xf0`g7\xbb$\x91o\xec\xdd\xbd\x9e\x8bb\xfc'
+response = OCSP_Response(s)
+
+= OCSP class : OCSP Response global checks
+assert(response.responseStatus.val == 0)
+assert(isinstance(response.responseBytes, OCSP_ResponseBytes))
+responseBytes = response.responseBytes
+assert(responseBytes.responseType == ASN1_OID("basic-response"))
+assert(responseBytes.signatureAlgorithm.algorithm == ASN1_OID("sha256WithRSAEncryption"))
+assert(responseBytes.signatureAlgorithm.parameters == ASN1_NULL(0))
+assert(responseBytes.signature.val_readable[:3] == "\x90\xef\xf9" and responseBytes.signature.val_readable[-3:] == "\x8bb\xfc")
+responseBytes.certs is None
+
+= OCSP class : OCSP ResponseData checks
+responseData = responseBytes.tbsResponseData
+assert(responseData.version is None)
+rID = responseData.responderID.responderID
+assert(isinstance(rID, OCSP_ByKey))
+assert(rID.byKey.val[:3] == "Qh\xff" and rID.byKey.val[-3:] == "Yr;")
+assert(responseData.producedAt == ASN1_GENERALIZED_TIME("20160914121000Z"))
+assert(len(responseData.responses) == 1)
+responseData.responseExtensions is None
+
+= OCSP class : OCSP SingleResponse checks
+singleResponse = responseData.responses[0]
+assert(singleResponse.certID.hashAlgorithm.algorithm == ASN1_OID("sha1"))
+assert(singleResponse.certID.hashAlgorithm.parameters == ASN1_NULL(0))
+assert(singleResponse.certID.issuerNameHash.val[:3] == "\xcf&\xf5" and singleResponse.certID.issuerNameHash.val[-3:] == "\x8e_\n")
+assert(singleResponse.certID.issuerKeyHash.val[:3] == "Qh\xff" and singleResponse.certID.issuerKeyHash.val[-3:] == "Yr;")
+assert(singleResponse.certID.serialNumber.val == 0x77a5dc3362301f989fe54f7f86f3e64)
+assert(isinstance(singleResponse.certStatus.certStatus, OCSP_GoodInfo))
+assert(singleResponse.thisUpdate == ASN1_GENERALIZED_TIME("20160914121000Z"))
+assert(singleResponse.nextUpdate == ASN1_GENERALIZED_TIME("20160921112500Z"))
+singleResponse.singleExtensions is None
+
+= OCSP class : OCSP Response reconstruction
+str(response) == s
+