From 1423b635de1a442490c17fa322b9df20a224ee41 Mon Sep 17 00:00:00 2001 From: rperez Date: Tue, 10 Sep 2019 09:45:30 +0200 Subject: [PATCH 1/3] Add support for curve x448 --- scapy/layers/tls/automaton_cli.py | 2 +- scapy/layers/tls/keyexchange_tls13.py | 25 ++++++++++++++++--------- test/tls/example_client.py | 2 ++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/scapy/layers/tls/automaton_cli.py b/scapy/layers/tls/automaton_cli.py index 7a6ad603c70..6e2ff8242dd 100644 --- a/scapy/layers/tls/automaton_cli.py +++ b/scapy/layers/tls/automaton_cli.py @@ -981,7 +981,7 @@ def TLS13_START(self): @ATMT.condition(TLS13_START) def tls13_should_add_ClientHello(self): # we have to use the legacy, plaintext TLS record here - supported_groups = ["secp256r1", "secp384r1"] + supported_groups = ["secp256r1", "secp384r1", "x448"] if conf.crypto_valid_advanced: supported_groups.append("x25519") self.add_record(is_tls13=False) diff --git a/scapy/layers/tls/keyexchange_tls13.py b/scapy/layers/tls/keyexchange_tls13.py index 6710af4e5b9..f8b1d82ff2a 100644 --- a/scapy/layers/tls/keyexchange_tls13.py +++ b/scapy/layers/tls/keyexchange_tls13.py @@ -26,6 +26,7 @@ from cryptography.hazmat.primitives.asymmetric import dh, ec if conf.crypto_valid_advanced: from cryptography.hazmat.primitives.asymmetric import x25519 + from cryptography.hazmat.primitives.asymmetric import x448 class KeyShareEntry(Packet): @@ -67,16 +68,19 @@ def create_privkey(self): pubkey = privkey.public_key() self.key_exchange = pubkey.public_numbers().y elif self.group in _tls_named_curves: - if _tls_named_curves[self.group] == "x25519": + if _tls_named_curves[self.group] in ["x25519", "x448"]: if conf.crypto_valid_advanced: - privkey = x25519.X25519PrivateKey.generate() + if _tls_named_curves[self.group] == "x25519": + privkey = x25519.X25519PrivateKey.generate() + else: + privkey = x448.X448PrivateKey.generate() self.privkey = privkey pubkey = privkey.public_key() self.key_exchange = pubkey.public_bytes( serialization.Encoding.Raw, serialization.PublicFormat.Raw ) - elif _tls_named_curves[self.group] != "x448": + else: curve = ec._CURVE_TYPES[_tls_named_curves[self.group]]() privkey = ec.generate_private_key(curve, default_backend()) self.privkey = privkey @@ -116,11 +120,14 @@ def register_pubkey(self): public_numbers = dh.DHPublicNumbers(self.key_exchange, pn) self.pubkey = public_numbers.public_key(default_backend()) elif self.group in _tls_named_curves: - if _tls_named_curves[self.group] == "x25519": + if _tls_named_curves[self.group] in ["x25519", "x448"]: if conf.crypto_valid_advanced: - import_point = x25519.X25519PublicKey.from_public_bytes + if _tls_named_curves[self.group] == "x25519": + import_point = x25519.X25519PublicKey.from_public_bytes + else: + import_point = x448.X448PublicKey.from_public_bytes self.pubkey = import_point(self.key_exchange) - elif _tls_named_curves[self.group] != "x448": + else: curve = ec._CURVE_TYPES[_tls_named_curves[self.group]]() try: # cryptography >= 2.5 import_point = ec.EllipticCurvePublicKey.from_encoded_point # noqa: E501 @@ -203,7 +210,7 @@ def post_build(self, pkt, pay): if group_name in six.itervalues(_tls_named_ffdh_groups): pms = privkey.exchange(pubkey) elif group_name in six.itervalues(_tls_named_curves): - if group_name == "x25519": + if group_name in ["x25519", "x448"]: pms = privkey.exchange(pubkey) else: pms = privkey.exchange(ec.ECDH(), pubkey) @@ -226,7 +233,7 @@ def post_dissection(self, r): if group_name in six.itervalues(_tls_named_ffdh_groups): pms = privkey.exchange(pubkey) elif group_name in six.itervalues(_tls_named_curves): - if group_name == "x25519": + if group_name in ["x25519", "x448"]: pms = privkey.exchange(pubkey) else: pms = privkey.exchange(ec.ECDH(), pubkey) @@ -237,7 +244,7 @@ def post_dissection(self, r): if group_name in six.itervalues(_tls_named_ffdh_groups): pms = privkey.exchange(pubkey) elif group_name in six.itervalues(_tls_named_curves): - if group_name == "x25519": + if group_name in ["x25519", "x448"]: pms = privkey.exchange(pubkey) else: pms = privkey.exchange(ec.ECDH(), pubkey) diff --git a/test/tls/example_client.py b/test/tls/example_client.py index b1a753f136a..c6792dd942a 100755 --- a/test/tls/example_client.py +++ b/test/tls/example_client.py @@ -43,6 +43,7 @@ help="Resumption master secret (for TLS 1.3)") parser.add_argument("--sni", help="Server Name Indication") +parser.add_argument("--curve", help="ECC group to advertise") parser.add_argument("--debug", action="store_const", const=5, default=0, help="Enter debug mode") parser.add_argument("server", nargs="?", default="127.0.0.1", @@ -94,6 +95,7 @@ resumption_master_secret=args.res_master, session_ticket_file_in=args.session_ticket_file_in, session_ticket_file_out=args.session_ticket_file_out, + curve=args.curve, debug=args.debug) t.run() From 6544c009e8b2698c0d1de288c30e1ebf197ee2db Mon Sep 17 00:00:00 2001 From: gpotter Date: Fri, 8 May 2020 22:26:40 +0200 Subject: [PATCH 2/3] Add x448 tests --- test/tls/tests_tls_netaccess.uts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/tls/tests_tls_netaccess.uts b/test/tls/tests_tls_netaccess.uts index ba61b4261ba..8cbb4b55a2f 100644 --- a/test/tls/tests_tls_netaccess.uts +++ b/test/tls/tests_tls_netaccess.uts @@ -322,6 +322,11 @@ test_tls_client("1303", "0304") test_tls_client("1305", "0304") += Testing TLS server and client with TLS 1.3 and TLS_AES_128_CCM_8_SHA256 and x448 +~ crypto_advanced + +test_tls_client("1305", "0304", curve="x448") + = Testing TLS server and client with TLS 1.3 and a retry ~ crypto_advanced From 1e9cf496d4b2bf4adb1a9a81ff59f10359b99321 Mon Sep 17 00:00:00 2001 From: gpotter Date: Fri, 8 May 2020 22:54:18 +0200 Subject: [PATCH 3/3] Credit Romain Perez --- scapy/layers/tls/automaton_cli.py | 4 ++-- scapy/layers/tls/automaton_srv.py | 4 ++-- scapy/layers/tls/handshake.py | 1 + scapy/layers/tls/keyexchange.py | 1 + scapy/layers/tls/keyexchange_tls13.py | 1 + scapy/layers/tls/record.py | 4 +++- scapy/layers/tls/record_tls13.py | 1 + scapy/layers/tls/session.py | 1 + 8 files changed, 12 insertions(+), 5 deletions(-) diff --git a/scapy/layers/tls/automaton_cli.py b/scapy/layers/tls/automaton_cli.py index 6e2ff8242dd..7ff76a3a972 100644 --- a/scapy/layers/tls/automaton_cli.py +++ b/scapy/layers/tls/automaton_cli.py @@ -1,14 +1,14 @@ # This file is part of Scapy # Copyright (C) 2007, 2008, 2009 Arnaud Ebalard # 2015, 2016, 2017 Maxence Tury +# 2019 Romain Perez # This program is published under a GPLv2 license """ TLS client automaton. This makes for a primitive TLS stack. Obviously you need rights for network access. -We support versions SSLv2 to TLS 1.2, along with many features. -There is no session resumption mechanism for now. +We support versions SSLv2 to TLS 1.3, along with many features. In order to run a client to tcp/50000 with one cipher suite of your choice: > from scapy.all import * diff --git a/scapy/layers/tls/automaton_srv.py b/scapy/layers/tls/automaton_srv.py index 156ed0ee1e1..4a2251b23fb 100644 --- a/scapy/layers/tls/automaton_srv.py +++ b/scapy/layers/tls/automaton_srv.py @@ -1,14 +1,14 @@ # This file is part of Scapy # Copyright (C) 2007, 2008, 2009 Arnaud Ebalard # 2015, 2016, 2017 Maxence Tury +# 2019 Romain Perez # This program is published under a GPLv2 license """ TLS server automaton. This makes for a primitive TLS stack. Obviously you need rights for network access. -We support versions SSLv2 to TLS 1.2, along with many features. -There is no session resumption mechanism for now. +We support versions SSLv2 to TLS 1.3, along with many features. In order to run a server listening on tcp/4433: > from scapy.all import * diff --git a/scapy/layers/tls/handshake.py b/scapy/layers/tls/handshake.py index 22c6e956da8..d7a60f734ca 100644 --- a/scapy/layers/tls/handshake.py +++ b/scapy/layers/tls/handshake.py @@ -1,6 +1,7 @@ # This file is part of Scapy # Copyright (C) 2007, 2008, 2009 Arnaud Ebalard # 2015, 2016, 2017 Maxence Tury +# 2019 Romain Perez # This program is published under a GPLv2 license """ diff --git a/scapy/layers/tls/keyexchange.py b/scapy/layers/tls/keyexchange.py index f23a4b341f9..5172af43f16 100644 --- a/scapy/layers/tls/keyexchange.py +++ b/scapy/layers/tls/keyexchange.py @@ -1,6 +1,7 @@ # This file is part of Scapy # Copyright (C) 2007, 2008, 2009 Arnaud Ebalard # 2015, 2016, 2017 Maxence Tury +# 2019 Romain Perez # This program is published under a GPLv2 license """ diff --git a/scapy/layers/tls/keyexchange_tls13.py b/scapy/layers/tls/keyexchange_tls13.py index f8b1d82ff2a..97b63465543 100644 --- a/scapy/layers/tls/keyexchange_tls13.py +++ b/scapy/layers/tls/keyexchange_tls13.py @@ -1,5 +1,6 @@ # This file is part of Scapy # Copyright (C) 2017 Maxence Tury +# 2019 Romain Perez # This program is published under a GPLv2 license """ diff --git a/scapy/layers/tls/record.py b/scapy/layers/tls/record.py index 505e9155cb8..32fb5e1eb6b 100644 --- a/scapy/layers/tls/record.py +++ b/scapy/layers/tls/record.py @@ -1,6 +1,8 @@ # This file is part of Scapy # Copyright (C) 2007, 2008, 2009 Arnaud Ebalard -# 2015, 2016, 2017 Maxence Tury +# 2015, 2016, 2017 Maxence Tury +# 2019 Romain Perez +# 2019 Gabriel Potter # This program is published under a GPLv2 license """ diff --git a/scapy/layers/tls/record_tls13.py b/scapy/layers/tls/record_tls13.py index 7e2211092e9..1147159586e 100644 --- a/scapy/layers/tls/record_tls13.py +++ b/scapy/layers/tls/record_tls13.py @@ -1,5 +1,6 @@ # This file is part of Scapy # Copyright (C) 2017 Maxence Tury +# 2019 Romain Perez # This program is published under a GPLv2 license """ diff --git a/scapy/layers/tls/session.py b/scapy/layers/tls/session.py index 96282d83927..df818b21189 100644 --- a/scapy/layers/tls/session.py +++ b/scapy/layers/tls/session.py @@ -1,6 +1,7 @@ # This file is part of Scapy # Copyright (C) 2007, 2008, 2009 Arnaud Ebalard # 2015, 2016, 2017 Maxence Tury +# 2019 Romain Perez # This program is published under a GPLv2 license """