ikev2: accept key exchange on CREATE_CHILD_SA
In RFC 7296, CREATE_CHILD_SA Exchange may contain the KE payload to enable stronger guarantees of forward secrecy. When the KEi payload is included in the CREATE_CHILD_SA request, responder should reply with the KEr payload and complete the key exchange, in accordance with the RFC. Type: improvement Signed-off-by: Atzm Watanabe <atzmism@gmail.com> Change-Id: I13cf6cf24359c11c3366757e585195bb7e999638
This commit is contained in:

committed by
Beno�t Ganne

parent
138f65c5b7
commit
c65921f774
File diff suppressed because it is too large
Load Diff
@ -313,6 +313,7 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
u16 notify_type;
|
||||
u8 kex;
|
||||
u8 protocol_id;
|
||||
u32 spi;
|
||||
u32 ispi;
|
||||
|
@ -296,9 +296,11 @@ class IKEv2SA(object):
|
||||
def complete_dh_data(self):
|
||||
self.dh_shared_secret = self.compute_secret()
|
||||
|
||||
def calc_child_keys(self):
|
||||
def calc_child_keys(self, kex=False):
|
||||
prf = self.ike_prf_alg.mod()
|
||||
s = self.i_nonce + self.r_nonce
|
||||
if kex:
|
||||
s = self.dh_shared_secret + s
|
||||
c = self.child_sas[0]
|
||||
|
||||
encr_key_len = self.esp_crypto_key_len
|
||||
@ -625,8 +627,8 @@ class IkePeer(VppTestCase):
|
||||
node_name = "/err/ikev2-%s/" % version + name
|
||||
self.assertEqual(count, self.statistics.get_err_counter(node_name))
|
||||
|
||||
def create_rekey_request(self):
|
||||
sa, first_payload = self.generate_auth_payload(is_rekey=True)
|
||||
def create_rekey_request(self, kex=False):
|
||||
sa, first_payload = self.generate_auth_payload(is_rekey=True, kex=kex)
|
||||
header = ikev2.IKEv2(
|
||||
init_SPI=self.sa.ispi,
|
||||
resp_SPI=self.sa.rspi,
|
||||
@ -1345,9 +1347,10 @@ class TemplateResponder(IkePeer):
|
||||
capture = self.pg0.get_capture(1)
|
||||
self.verify_sa_init(capture[0])
|
||||
|
||||
def generate_auth_payload(self, last_payload=None, is_rekey=False):
|
||||
def generate_auth_payload(self, last_payload=None, is_rekey=False, kex=False):
|
||||
tr_attr = self.sa.esp_crypto_attr()
|
||||
last_payload = last_payload or "Notify"
|
||||
trans_nb = 4
|
||||
trans = (
|
||||
ikev2.IKEv2_payload_Transform(
|
||||
transform_type="Encryption",
|
||||
@ -1366,9 +1369,20 @@ class TemplateResponder(IkePeer):
|
||||
)
|
||||
)
|
||||
|
||||
if kex:
|
||||
trans_nb += 1
|
||||
trans /= ikev2.IKEv2_payload_Transform(
|
||||
transform_type="GroupDesc", transform_id=self.sa.ike_dh
|
||||
)
|
||||
|
||||
c = self.sa.child_sas[0]
|
||||
props = ikev2.IKEv2_payload_Proposal(
|
||||
proposal=1, proto="ESP", SPIsize=4, SPI=c.ispi, trans_nb=4, trans=trans
|
||||
proposal=1,
|
||||
proto="ESP",
|
||||
SPIsize=4,
|
||||
SPI=c.ispi,
|
||||
trans_nb=trans_nb,
|
||||
trans=trans,
|
||||
)
|
||||
|
||||
tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4)
|
||||
@ -1389,8 +1403,18 @@ class TemplateResponder(IkePeer):
|
||||
|
||||
if is_rekey:
|
||||
first_payload = "Nonce"
|
||||
if kex:
|
||||
head = ikev2.IKEv2_payload_Nonce(
|
||||
load=self.sa.i_nonce, next_payload="KE"
|
||||
) / ikev2.IKEv2_payload_KE(
|
||||
group=self.sa.ike_dh, load=self.sa.my_dh_pub_key, next_payload="SA"
|
||||
)
|
||||
else:
|
||||
head = ikev2.IKEv2_payload_Nonce(
|
||||
load=self.sa.i_nonce, next_payload="SA"
|
||||
)
|
||||
plain = (
|
||||
ikev2.IKEv2_payload_Nonce(load=self.sa.i_nonce, next_payload="SA")
|
||||
head
|
||||
/ plain
|
||||
/ ikev2.IKEv2_payload_Notify(
|
||||
type="REKEY_SA",
|
||||
@ -2079,8 +2103,12 @@ class TestResponderDpd(TestResponderPsk):
|
||||
class TestResponderRekey(TestResponderPsk):
|
||||
"""test ikev2 responder - rekey"""
|
||||
|
||||
WITH_KEX = False
|
||||
|
||||
def send_rekey_from_initiator(self):
|
||||
packet = self.create_rekey_request()
|
||||
if self.WITH_KEX:
|
||||
self.sa.generate_dh_data()
|
||||
packet = self.create_rekey_request(kex=self.WITH_KEX)
|
||||
self.pg0.add_stream(packet)
|
||||
self.pg0.enable_capture()
|
||||
self.pg_start()
|
||||
@ -2095,11 +2123,14 @@ class TestResponderRekey(TestResponderPsk):
|
||||
self.sa.r_nonce = sa[ikev2.IKEv2_payload_Nonce].load
|
||||
# update new responder SPI
|
||||
self.sa.child_sas[0].rspi = prop.SPI
|
||||
if self.WITH_KEX:
|
||||
self.sa.r_dh_data = sa[ikev2.IKEv2_payload_KE].load
|
||||
self.sa.complete_dh_data()
|
||||
self.sa.calc_child_keys(kex=self.WITH_KEX)
|
||||
|
||||
def test_responder(self):
|
||||
super(TestResponderRekey, self).test_responder()
|
||||
self.process_rekey_response(self.send_rekey_from_initiator())
|
||||
self.sa.calc_child_keys()
|
||||
self.verify_ike_sas()
|
||||
self.verify_ipsec_sas(is_rekey=True)
|
||||
self.assert_counter(1, "rekey_req", "ip4")
|
||||
@ -2128,11 +2159,24 @@ class TestResponderRekeyRepeat(TestResponderRekey):
|
||||
else:
|
||||
self.fail("old IPsec SA not expired")
|
||||
self.process_rekey_response(self.send_rekey_from_initiator())
|
||||
self.sa.calc_child_keys()
|
||||
self.verify_ike_sas()
|
||||
self.verify_ipsec_sas(sa_count=3)
|
||||
|
||||
|
||||
@tag_fixme_vpp_workers
|
||||
class TestResponderRekeyKEX(TestResponderRekey):
|
||||
"""test ikev2 responder - rekey with key exchange"""
|
||||
|
||||
WITH_KEX = True
|
||||
|
||||
|
||||
@tag_fixme_vpp_workers
|
||||
class TestResponderRekeyRepeatKEX(TestResponderRekeyRepeat):
|
||||
"""test ikev2 responder - rekey repeat with key exchange"""
|
||||
|
||||
WITH_KEX = True
|
||||
|
||||
|
||||
class TestResponderVrf(TestResponderPsk, Ikev2Params):
|
||||
"""test ikev2 responder - non-default table id"""
|
||||
|
||||
|
Reference in New Issue
Block a user