def configure_profile(self, cfg): p = Profile(self, cfg['name']) p.add_local_id(id_type=cfg['loc_id'][0], data=cfg['loc_id'][1]) p.add_remote_id(id_type=cfg['rem_id'][0], data=cfg['rem_id'][1]) p.add_local_ts(**cfg['loc_ts']) p.add_remote_ts(**cfg['rem_ts']) p.add_responder(cfg['responder']) p.add_ike_transforms(cfg['ike_ts']) p.add_esp_transforms(cfg['esp_ts']) p.add_auth(**cfg['auth']) p.set_udp_encap(cfg['udp_encap']) p.set_ipsec_over_udp_port(cfg['ipsec_over_udp_port']) if 'lifetime_data' in cfg: p.set_lifetime_data(cfg['lifetime_data']) if 'tun_itf' in cfg: p.set_tunnel_interface(cfg['tun_itf']) p.add_vpp_config() return p
class Ikev2Params(object): def config_params(self, params={}): ec = VppEnum.vl_api_ipsec_crypto_alg_t ei = VppEnum.vl_api_ipsec_integ_alg_t self.vpp_enums = { 'AES-CBC-128': ec.IPSEC_API_CRYPTO_ALG_AES_CBC_128, 'AES-CBC-192': ec.IPSEC_API_CRYPTO_ALG_AES_CBC_192, 'AES-CBC-256': ec.IPSEC_API_CRYPTO_ALG_AES_CBC_256, 'AES-GCM-16ICV-128': ec.IPSEC_API_CRYPTO_ALG_AES_GCM_128, 'AES-GCM-16ICV-192': ec.IPSEC_API_CRYPTO_ALG_AES_GCM_192, 'AES-GCM-16ICV-256': ec.IPSEC_API_CRYPTO_ALG_AES_GCM_256, 'HMAC-SHA1-96': ei.IPSEC_API_INTEG_ALG_SHA1_96, 'SHA2-256-128': ei.IPSEC_API_INTEG_ALG_SHA_256_128, 'SHA2-384-192': ei.IPSEC_API_INTEG_ALG_SHA_384_192, 'SHA2-512-256': ei.IPSEC_API_INTEG_ALG_SHA_512_256 } is_natt = 'natt' in params and params['natt'] or False self.p = Profile(self, 'pr1') if 'auth' in params and params['auth'] == 'rsa-sig': auth_method = 'rsa-sig' work_dir = os.getenv('BR') + '/../src/plugins/ikev2/test/certs/' self.vapi.ikev2_set_local_key(key_file=work_dir + params['server-key']) client_file = work_dir + params['client-cert'] server_pem = open(work_dir + params['server-cert']).read() client_priv = open(work_dir + params['client-key']).read() client_priv = load_pem_private_key(str.encode(client_priv), None, default_backend()) self.peer_cert = x509.load_pem_x509_certificate( str.encode(server_pem), default_backend()) self.p.add_auth(method='rsa-sig', data=str.encode(client_file)) auth_data = None else: auth_data = b'$3cr3tpa$$w0rd' self.p.add_auth(method='shared-key', data=auth_data) auth_method = 'shared-key' client_priv = None self.p.add_local_id(id_type='fqdn', data=b'vpp.home') self.p.add_remote_id(id_type='fqdn', data=b'roadwarrior.example.com') self.p.add_local_ts(start_addr='10.10.10.0', end_addr='10.10.10.255') self.p.add_remote_ts(start_addr='10.0.0.0', end_addr='10.0.0.255') self.sa = IKEv2SA(self, i_id=self.p.remote_id['data'], r_id=self.p.local_id['data'], id_type=self.p.local_id['id_type'], natt=is_natt, priv_key=client_priv, auth_method=auth_method, auth_data=auth_data, local_ts=self.p.remote_ts, remote_ts=self.p.local_ts) ike_crypto = ('AES-CBC', 32) if 'ike-crypto' not in params else\ params['ike-crypto'] ike_integ = 'HMAC-SHA1-96' if 'ike-integ' not in params else\ params['ike-integ'] ike_dh = '2048MODPgr' if 'ike-dh' not in params else params['ike-dh'] esp_crypto = ('AES-CBC', 32) if 'esp-crypto' not in params else\ params['esp-crypto'] esp_integ = 'HMAC-SHA1-96' if 'esp-integ' not in params else\ params['esp-integ'] self.sa.set_ike_props(crypto=ike_crypto[0], crypto_key_len=ike_crypto[1], integ=ike_integ, prf='PRF_HMAC_SHA2_256', dh=ike_dh) self.sa.set_esp_props(crypto=esp_crypto[0], crypto_key_len=esp_crypto[1], integ=esp_integ)
class TestResponder(VppTestCase): """ responder test """ @classmethod def setUpClass(cls): import scapy.contrib.ikev2 as _ikev2 globals()['ikev2'] = _ikev2 super(TestResponder, cls).setUpClass() cls.create_pg_interfaces(range(2)) for i in cls.pg_interfaces: i.admin_up() i.config_ip4() i.resolve_arp() @classmethod def tearDownClass(cls): super(TestResponder, cls).tearDownClass() def setUp(self): super(TestResponder, self).setUp() self.config_tc() def config_tc(self): self.p = Profile(self, 'pr1') self.p.add_auth(method='shared-key', data=b'$3cr3tpa$$w0rd') self.p.add_local_id(id_type='fqdn', data=b'vpp.home') self.p.add_remote_id(id_type='fqdn', data=b'roadwarrior.example.com') self.p.add_local_ts(start_addr=0x0a0a0a0, end_addr=0x0a0a0aff) self.p.add_remote_ts(start_addr=0xa000000, end_addr=0xa0000ff) self.p.add_vpp_config() self.sa = IKEv2SA(self, i_id=self.p.remote_id['data'], r_id=self.p.local_id['data'], is_initiator=True, auth_data=self.p.auth['data'], id_type=self.p.local_id['id_type'], local_ts=self.p.remote_ts, remote_ts=self.p.local_ts) self.sa.set_ike_props(crypto='AES-CBC', crypto_key_len=32, integ='HMAC-SHA1-96', prf='PRF_HMAC_SHA2_256', dh='2048MODPgr') self.sa.set_esp_props(crypto='AES-CBC', crypto_key_len=32, integ='HMAC-SHA1-96') self.sa.generate_dh_data() def create_ike_msg(self, src_if, msg, sport=500, dport=500): return (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / IP(src=src_if.remote_ip4, dst=src_if.local_ip4) / UDP(sport=sport, dport=dport) / msg) def send_sa_init(self): tr_attr = self.sa.ike_crypto_attr() trans = ( ikev2.IKEv2_payload_Transform(transform_type='Encryption', transform_id=self.sa.ike_crypto, length=tr_attr[1], key_length=tr_attr[0]) / ikev2.IKEv2_payload_Transform(transform_type='Integrity', transform_id=self.sa.ike_integ) / ikev2.IKEv2_payload_Transform( transform_type='PRF', transform_id=self.sa.ike_prf_alg.name) / ikev2.IKEv2_payload_Transform(transform_type='GroupDesc', transform_id=self.sa.ike_dh)) props = (ikev2.IKEv2_payload_Proposal(proposal=1, proto='IKEv2', trans_nb=4, trans=trans)) self.sa.init_req_packet = ( ikev2.IKEv2(init_SPI=self.sa.ispi, flags='Initiator', exch_type='IKE_SA_INIT') / ikev2.IKEv2_payload_SA(next_payload='KE', prop=props) / ikev2.IKEv2_payload_KE(next_payload='Nonce', group=self.sa.ike_dh, load=self.sa.dh_pub_key()) / ikev2.IKEv2_payload_Nonce(load=self.sa.i_nonce)) ike_msg = self.create_ike_msg(self.pg0, self.sa.init_req_packet) self.pg0.add_stream(ike_msg) self.pg0.enable_capture() self.pg_start() capture = self.pg0.get_capture(1) self.verify_sa_init(capture[0]) def send_sa_auth(self): tr_attr = self.sa.esp_crypto_attr() trans = ( ikev2.IKEv2_payload_Transform(transform_type='Encryption', transform_id=self.sa.esp_crypto, length=tr_attr[1], key_length=tr_attr[0]) / ikev2.IKEv2_payload_Transform(transform_type='Integrity', transform_id=self.sa.esp_integ) / ikev2.IKEv2_payload_Transform( transform_type='Extended Sequence Number', transform_id='No ESN') / ikev2.IKEv2_payload_Transform( transform_type='Extended Sequence Number', transform_id='ESN')) props = (ikev2.IKEv2_payload_Proposal(proposal=1, proto='ESP', SPIsize=4, SPI=os.urandom(4), trans_nb=4, trans=trans)) tsi, tsr = self.sa.generate_ts() plain = (ikev2.IKEv2_payload_IDi( next_payload='IDr', IDtype=self.sa.id_type, load=self.sa.i_id) / ikev2.IKEv2_payload_IDr(next_payload='AUTH', IDtype=self.sa.id_type, load=self.sa.r_id) / ikev2.IKEv2_payload_AUTH( next_payload='SA', auth_type=2, load=self.sa.auth_data) / ikev2.IKEv2_payload_SA(next_payload='TSi', prop=props) / ikev2.IKEv2_payload_TSi(next_payload='TSr', number_of_TSs=len(tsi), traffic_selector=tsi) / ikev2.IKEv2_payload_TSr(next_payload='Notify', number_of_TSs=len(tsr), traffic_selector=tsr) / ikev2.IKEv2_payload_Notify(type='INITIAL_CONTACT')) encr = self.sa.encrypt(raw(plain)) trunc_len = self.sa.ike_integ_alg.trunc_len plen = len(encr) + len(ikev2.IKEv2_payload_Encrypted()) + trunc_len tlen = plen + len(ikev2.IKEv2()) sk_p = ikev2.IKEv2_payload_Encrypted(next_payload='IDi', length=plen, load=encr) sa_auth = (ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi, length=tlen, flags='Initiator', exch_type='IKE_AUTH', id=1)) sa_auth /= sk_p integ_data = raw(sa_auth) hmac_data = self.sa.compute_hmac(self.sa.ike_integ_alg.mod(), self.sa.my_authkey, integ_data) sa_auth = sa_auth / Raw(hmac_data[:trunc_len]) assert (len(sa_auth) == tlen) packet = self.create_ike_msg(self.pg0, sa_auth) self.pg0.add_stream(packet) self.pg0.enable_capture() self.pg_start() capture = self.pg0.get_capture(1) self.verify_sa_auth(capture[0]) def verify_sa_init(self, packet): ih = packet[ikev2.IKEv2] self.assertEqual(ih.exch_type, 34) self.assertTrue('Response' in ih.flags) self.assertEqual(ih.init_SPI, self.sa.ispi) self.assertNotEqual(ih.resp_SPI, 0) self.sa.rspi = ih.resp_SPI try: sa = ih[ikev2.IKEv2_payload_SA] self.sa.r_nonce = ih[ikev2.IKEv2_payload_Nonce].load self.sa.r_dh_data = ih[ikev2.IKEv2_payload_KE].load except AttributeError as e: self.logger.error("unexpected reply: SA/Nonce/KE payload found!") raise self.sa.complete_dh_data() self.sa.calc_keys() self.sa.auth_init() def verify_sa_auth(self, packet): try: ike = packet[ikev2.IKEv2] ep = packet[ikev2.IKEv2_payload_Encrypted] except KeyError as e: self.logger.error("unexpected reply: no IKEv2/Encrypt payload!") raise plain = self.sa.hmac_and_decrypt(ike) self.sa.calc_child_keys() def verify_child_sas(self): sas = self.vapi.ipsec_sa_dump() self.assertEqual(len(sas), 2) sa0 = sas[0].entry sa1 = sas[1].entry c = self.sa.child_sas[0] # verify crypto keys self.assertEqual(sa0.crypto_key.length, len(c.sk_er)) self.assertEqual(sa1.crypto_key.length, len(c.sk_ei)) self.assertEqual(sa0.crypto_key.data[:len(c.sk_er)], c.sk_er) self.assertEqual(sa1.crypto_key.data[:len(c.sk_ei)], c.sk_ei) # verify integ keys self.assertEqual(sa0.integrity_key.length, len(c.sk_ar)) self.assertEqual(sa1.integrity_key.length, len(c.sk_ai)) self.assertEqual(sa0.integrity_key.data[:len(c.sk_ar)], c.sk_ar) self.assertEqual(sa1.integrity_key.data[:len(c.sk_ai)], c.sk_ai) def test_responder(self): self.send_sa_init() self.send_sa_auth() self.verify_child_sas()