tintinweb / scapy-ssl_tls

SSL/TLS layers for scapy the interactive packet manipulation tool
GNU General Public License v2.0
419 stars 156 forks source link

Handling of curve25519 and curve448 ServerKeyExchange #167

Open phlsc opened 2 years ago

phlsc commented 2 years ago

I am using scapy-ssl_tls (version 2.3.2, Python 2.7.18 on Manjaro Linux) to perform several security test against webservers. At some point the server resonds with curve x25519 in the ECDH Server Params of the ServerKeyExchange: From Wireshark:

EC Diffie-Hellman Server Params
    Curve Type: named_curve (0x03)
    Named Curve: x25519 (0x001d)
    Pubkey Length: 32
    Pubkey: 1b3b2c6001bdce795d32a7157d1e5d25bb53978a80539b67c79d9a9b2890397d
    Signature Algorithm: rsa_pkcs1_sha256 (0x0401)
    Signature Length: 256
    Signature: 20ff9d177278775db10e00157909851f3b33fa610171a854e60c7ff6f7e0a5ee91d63a72…

scapy-ssl_tls raises a ValueError here:

Traceback (most recent call last):
  File "./testssl-python/clienthello.py", line 196, in <module>
    if test_tls_1_2_phase_two(target_host):
  File "./testssl-python/clienthello.py", line 147, in test_tls_1_2_phase_two
    return test_vulnerable_with_handshake(TLSVersion.TLS_1_2, cipher_suites, target)
  File "./testssl-python/clienthello.py", line 49, in test_vulnerable_with_handshake
    response = tls_do_round_trip(tls_socket, client_hello)
  File "./testssl-python/venv/lib/python2.7/site-packages/scapy_ssl_tls/ssl_tls.py", line 1491, in tls_do_round_trip
    resp = tls_socket.recvall()
  File "./testssl-python/venv/lib/python2.7/site-packages/scapy_ssl_tls/ssl_tls.py", line 1284, in recvall
    records = TLS("".join(resp), ctx=self.tls_ctx, _origin=self._get_pkt_origin('in'))
  File "./testssl-python/venv/lib/python2.7/site-packages/scapy/base_classes.py", line 196, in __call__
    i.__init__(*args, **kargs)
  File "./testssl-python/venv/lib/python2.7/site-packages/scapy_ssl_tls/ssl_tls.py", line 1316, in __init__
    Packet.__init__(self, *args, **fields)
  File "./testssl-python/venv/lib/python2.7/site-packages/scapy/packet.py", line 85, in __init__
    self.dissect(_pkt)
  File "./testssl-python/venv/lib/python2.7/site-packages/scapy/packet.py", line 618, in dissect
    s = self.do_dissect(s)
  File "./testssl-python/venv/lib/python2.7/site-packages/scapy_ssl_tls/ssl_tls.py", line 1349, in do_dissect
    self.tls_ctx.insert(payload, origin=self._origin)
  File "./testssl-python/venv/lib/python2.7/site-packages/scapy_ssl_tls/ssl_tls_crypto.py", line 215, in insert
    self._process(pkt, origin=origin)
  File "./testssl-python/venv/lib/python2.7/site-packages/scapy_ssl_tls/ssl_tls_crypto.py", line 529, in _process
    self.__handle_server_kex(pkt[tls.TLSServerKeyExchange])
  File "./testssl-python/venv/lib/python2.7/site-packages/scapy_ssl_tls/ssl_tls_crypto.py", line 373, in __handle_server_kex
    point = tlsk.ansi_str_to_point(server_kex[tls.TLSServerECDHParams].p)
  File "./testssl-python/venv/lib/python2.7/site-packages/scapy_ssl_tls/ssl_tls_keystore.py", line 97, in ansi_str_to_point
    raise ValueError("ANSI octet string missing point prefix (0x04)")
ValueError: ANSI octet string missing point prefix (0x04)

Process finished with exit code 1

This is wrong behavior, as the 0x04 prefix only applies to NIST curves (see RFC 8422, Sect. 5.4), not other ones like x25519 or x448.

Here is the snippet, that calls the tls_do_round_trip function:

    if version not in TLS_SERVER_VERSIONS_SUPPORTED:
        return False

    s = socket.socket()
    ciphers = list(ciphers)
    with TLSSocket(sock=s, client=True) as tls_socket:
        try:
            tls_socket.connect(target)
        except socket.timeout:
            print("timeout")
        else:
            vulnerable = True
            client_hello = TLSRecord(version=TLSVersion.TLS_1_0) /  \
               TLSHandshakes(handshakes=[TLSHandshake() /
                             TLSClientHello(version=version,
                                            cipher_suites=ciphers,
                                            extensions=[
                                                TLSExtension() /
                                                TLSExtSignatureAlgorithms(algs=signature_algorithms.TESTSSL_SIG_ALGS),
                                                TLSExtension() /
                                                TLSExtSupportedGroups(named_group_list=supported_groups.TESTSSL_SUPPORTED_GROUPS)
                                            ])
                             ])
            try:
                response = tls_do_round_trip(tls_socket, client_hello)
[...]

Is it planned, that this library will support x25519 and x448 curves at all or is this out of scope? In the latter case, maybe it would be nice to raise a NotImplementedError here?