from ipaddress import ip_network, ip_address
from enum import Enum, IntEnum
-from robot.api import logger
from resources.libraries.python.PapiExecutor import PapiExecutor
-from resources.libraries.python.PapiErrors import PapiError, PapiCommandError
from resources.libraries.python.topology import Topology
-from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal
+from resources.libraries.python.VatExecutor import VatExecutor
from resources.libraries.python.VatJsonUtil import VatJsonUtil
AES_CBC_192 = ('aes-cbc-192', 'AES-CBC', 24)
AES_CBC_256 = ('aes-cbc-256', 'AES-CBC', 32)
AES_GCM_128 = ('aes-gcm-128', 'AES-GCM', 20)
+ AES_GCM_256 = ('aes-gcm-256', 'AES-GCM', 40)
def __init__(self, alg_name, scapy_name, key_len):
self.alg_name = alg_name
SHA_384_192 = ('sha-384-192', 'SHA2-384-192', 48)
SHA_512_256 = ('sha-512-256', 'SHA2-512-256', 64)
AES_GCM_128 = ('aes-gcm-128', 'AES-GCM', 20)
+ AES_GCM_256 = ('aes-gcm-256', 'AES-GCM', 40)
def __init__(self, alg_name, scapy_name, key_len):
self.alg_name = alg_name
class IPsecProto(IntEnum):
"""IPsec protocol."""
ESP = 1
- AH = 0
+ SEC_AH = 0
class IPsecUtil(object):
"""
return CryptoAlg.AES_GCM_128
+ @staticmethod
+ def crypto_alg_aes_gcm_256():
+ """Return encryption algorithm aes-gcm-256.
+
+ :returns: CryptoAlg enum AES_GCM_128 object.
+ :rtype: CryptoAlg
+ """
+ return CryptoAlg.AES_GCM_256
+
@staticmethod
def get_crypto_alg_key_len(crypto_alg):
"""Return encryption algorithm key length.
"""
return IntegAlg.AES_GCM_128
+ @staticmethod
+ def integ_alg_aes_gcm_256():
+ """Return integrity algorithm AES-GCM-256.
+
+ :returns: IntegAlg enum AES_GCM_256 object.
+ :rtype: IntegAlg
+ """
+ return IntegAlg.AES_GCM_256
+
@staticmethod
def get_integ_alg_key_len(integ_alg):
"""Return integrity algorithm key length.
:returns: IPsecProto enum AH object.
:rtype: IPsecProto
"""
- return int(IPsecProto.AH)
+ return int(IPsecProto.SEC_AH)
@staticmethod
def vpp_ipsec_select_backend(node, protocol, index=1):
:type node: dict
:type protocol: IPsecProto
:type index: int
+ :raises RuntimeError: If failed to select IPsec backend or if no API
+ reply received.
"""
- # TODO: move composition of api data to separate method
- api_data = list()
- api = dict(api_name='ipsec_select_backend')
- api_args = dict(protocol=protocol)
- api_args['index'] = index
- api['api_args'] = api_args
- api_data.append(api)
-
- api_reply = None
- with PapiExecutor(node) as papi_executor:
- papi_executor.execute_papi(api_data)
- try:
- papi_executor.papi_should_have_passed()
- except AssertionError:
- raise PapiError('Failed to select IPsec backend on host {host}'.
- format(host=node['host']))
- api_reply = papi_executor.get_papi_reply()
-
- if api_reply is not None:
- api_r = api_reply[0]['api_reply']['ipsec_select_backend_reply']
- if api_r['retval'] == 0:
- logger.trace('IPsec backend successfully selected on host '
- '{host}'.format(host=node['host']))
- else:
- raise PapiError('Failed to select IPsec backend on host {host}'.
- format(host=node['host']))
- else:
- raise PapiError('No reply received for ipsec_select_backend API '
- 'command on host {host}'.format(host=node['host']))
+
+ cmd = 'ipsec_select_backend'
+ cmd_reply = 'ipsec_select_backend_reply'
+ err_msg = 'Failed to select IPsec backend on host {host}'.format(
+ host=node['host'])
+ args = dict(protocol=protocol, index=index)
+ with PapiExecutor(node) as papi_exec:
+ papi_resp = papi_exec.add(cmd, **args).execute_should_pass(err_msg)
+ data = papi_resp.reply[0]['api_reply'][cmd_reply]
+ if data['retval'] != 0:
+ raise RuntimeError('Failed to select IPsec backend on host {host}'.
+ format(host=node['host']))
@staticmethod
def vpp_ipsec_backend_dump(node):
:param node: VPP node to dump IPsec backend on.
:type node: dict
"""
- # TODO: move composition of api data to separate method
- api_data = list()
- api = dict(api_name='ipsec_backend_dump')
- api_args = dict()
- api['api_args'] = api_args
- api_data.append(api)
-
- api_reply = None
- with PapiExecutor(node) as papi_executor:
- papi_executor.execute_papi(api_data)
- try:
- papi_executor.papi_should_have_passed()
- except AssertionError:
- raise PapiError('Failed to dump IPsec backends on host {host}'.
- format(host=node['host']))
- api_reply = papi_executor.get_papi_reply()
-
- if api_reply is not None:
- # api_r = api_reply[0]['api_reply']['ipsec_select_backend_reply']
- # if api_r['retval'] == 0:
- # logger.trace('IPsec backend successfully selected on host '
- # '{host}'.format(host=node['host']))
- # else:
- # raise PapiError('Failed to select IPsec backend on host {host}'.
- # format(host=node['host']))
- logger.trace('IPsec backend dump\n{dump}'.format(dump=api_reply))
- else:
- raise PapiError('No reply received for ipsec_select_backend API '
- 'command on host {host}'.format(host=node['host']))
+
+ err_msg = 'Failed to dump IPsec backends on host {host}'.format(
+ host=node['host'])
+ with PapiExecutor(node) as papi_exec:
+ papi_exec.add('ipsec_backend_dump').execute_should_pass(
+ err_msg, process_reply=False)
@staticmethod
def vpp_ipsec_add_sad_entry(node, sad_id, spi, crypto_alg, crypto_key,
"""
ckey = crypto_key.encode('hex')
ikey = integ_key.encode('hex')
- tunnel = 'tunnel_src {0} tunnel_dst {1}'.format(tunnel_src, tunnel_dst)\
+ tunnel = 'tunnel-src {0} tunnel-dst {1}'.format(tunnel_src, tunnel_dst)\
if tunnel_src is not None and tunnel_dst is not None else ''
out = VatExecutor.cmd_from_template(node,
tmp_filename = '/tmp/ipsec_sad_{0}_add_del_entry.script'.format(sad_id)
ckey = crypto_key.encode('hex')
ikey = integ_key.encode('hex')
- tunnel = 'tunnel_src {0} tunnel_dst {1}'.format(tunnel_src, tunnel_dst)\
+ tunnel = 'tunnel-src {0} tunnel-dst {1}'.format(tunnel_src, tunnel_dst)\
if tunnel_src is not None and tunnel_dst is not None else ''
- integ = 'integ_alg {0} integ_key {1}'.format(integ_alg.alg_name, ikey)\
- if crypto_alg.alg_name != 'aes-gcm-128' else ''
+ integ = 'integ-alg {0} integ-key {1}'.format(integ_alg.alg_name, ikey)\
+ if crypto_alg.alg_name != 'aes-gcm-128' and \
+ crypto_alg.alg_name != 'aes-gcm-256' else ''
with open(tmp_filename, 'w') as tmp_file:
for i in range(0, n_entries):
- buf_str = 'ipsec_sad_add_del_entry esp sad_id {0} spi {1} ' \
- 'crypto_alg {2} crypto_key {3} {4} {5}\n'.format(
+ buf_str = 'exec ipsec sa add {0} esp spi {1} ' \
+ 'crypto-alg {2} crypto-key {3} {4} {5}\n'.format(
sad_id+i, spi+i, crypto_alg.alg_name, ckey, integ,
tunnel)
tmp_file.write(buf_str)
ckey = crypto_key.encode('hex')
ikey = integ_key.encode('hex')
- out = VatExecutor.cmd_from_template(node,
- 'ipsec/ipsec_sa_set_key.vat',
- sa_id=sa_id,
- ckey=ckey, ikey=ikey)
+ out = VatExecutor.cmd_from_template(
+ node, 'ipsec/ipsec_sa_set_key.vat', json_param=False, sa_id=sa_id,
+ ckey=ckey, ikey=ikey)
VatJsonUtil.verify_vat_retval(
out[0],
err_msg='Update SA key failed on {0}'.format(node['host']))
interface, spd_id, node['host']))
@staticmethod
- def vpp_ipsec_spd_add_entry(node, spd_id, priority, action, inbound=True,
- sa_id=None, laddr_range=None, raddr_range=None,
- proto=None, lport_range=None, rport_range=None):
+ def vpp_ipsec_policy_add(node, spd_id, priority, action, inbound=True,
+ sa_id=None, laddr_range=None, raddr_range=None,
+ proto=None, lport_range=None, rport_range=None,
+ is_ipv6=False):
"""Create Security Policy Database entry on the VPP node.
:param node: VPP node to add SPD entry on.
<port_start>-<port_end>.
:param rport_range: Policy selector remote TCP/UDP port range in format
<port_start>-<port_end>.
+ :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
+ not defined so it will default to address ::/0, otherwise False.
:type node: dict
:type spd_id: int
:type priority: int
:type proto: int
:type lport_range: string
:type rport_range: string
+ :type is_ipv6: bool
"""
direction = 'inbound' if inbound else 'outbound'
+ if laddr_range is None and is_ipv6:
+ laddr_range = '::/0'
+
+ if raddr_range is None and is_ipv6:
+ raddr_range = '::/0'
+
act_str = action.value
if PolicyAction.PROTECT == action and sa_id is not None:
- act_str += 'sa_id {0}'.format(sa_id)
+ act_str += ' sa {0}'.format(sa_id)
selector = ''
if laddr_range is not None:
net = ip_network(unicode(laddr_range), strict=False)
- selector += 'laddr_start {0} laddr_stop {1} '.format(
+ selector += 'local-ip-range {0} - {1} '.format(
net.network_address, net.broadcast_address)
if raddr_range is not None:
net = ip_network(unicode(raddr_range), strict=False)
- selector += 'raddr_start {0} raddr_stop {1} '.format(
+ selector += 'remote-ip-range {0} - {1} '.format(
net.network_address, net.broadcast_address)
if proto is not None:
selector += 'protocol {0} '.format(proto)
if lport_range is not None:
- selector += 'lport_start {p[0]} lport_stop {p[1]} '.format(
- p=lport_range.split('-'))
+ selector += 'local-port-range {0} '.format(lport_range)
if rport_range is not None:
- selector += 'rport_start {p[0]} rport_stop {p[1]} '.format(
- p=rport_range.split('-'))
+ selector += 'remote-port-range {0} '.format(rport_range)
- out = VatExecutor.cmd_from_template(node,
- 'ipsec/ipsec_spd_add_entry.vat',
- spd_id=spd_id, priority=priority,
- action=act_str, direction=direction,
- selector=selector)
+ out = VatExecutor.cmd_from_template(
+ node, 'ipsec/ipsec_policy_add.vat', json_param=False, spd_id=spd_id,
+ priority=priority, action=act_str, direction=direction,
+ selector=selector)
VatJsonUtil.verify_vat_retval(
out[0],
- err_msg='Add entry to SPD {0} failed on {1}'.format(spd_id,
- node['host']))
+ err_msg='Add IPsec policy ID {0} failed on {1}'.format(
+ spd_id, node['host']))
@staticmethod
def vpp_ipsec_spd_add_entries(node, n_entries, spd_id, priority, inbound,
direction = 'inbound' if inbound else 'outbound'
addr_incr = 1 << (32 - raddr_range)
addr_ip = int(ip_address(unicode(raddr_ip)))
- start_str = 'ipsec_spd_add_del_entry spd_id {0} priority {1} {2} ' \
- 'action protect sa_id'.format(spd_id, priority, direction)
+ start_str = 'exec ipsec policy add spd {0} priority {1} {2} ' \
+ 'action protect sa'.format(spd_id, priority, direction)
with open(tmp_filename, 'w') as tmp_file:
for i in range(0, n_entries):
r_ip_s = ip_address(addr_ip + addr_incr * i)
r_ip_e = ip_address(addr_ip + addr_incr * (i+1) - 1)
- buf_str = '{0} {1} raddr_start {2} raddr_stop {3}\n'.format(
+ buf_str = '{0} {1} remote-ip-range {2} - {3}\n'.format(
start_str, sa_id+i, r_ip_s, r_ip_e)
tmp_file.write(buf_str)
vat = VatExecutor()
with open(tmp_fn1, 'w') as tmp_f1, open(tmp_fn2, 'w') as tmp_f2:
for i in range(0, n_tunnels):
integ = ''
- # if crypto_alg.alg_name != 'aes-gcm-128':
if not crypto_alg.alg_name.startswith('aes-gcm-'):
integ = 'integ_alg {integ_alg} '\
'local_integ_key {local_integ_key} '\
IPsecUtil.vpp_ipsec_add_spd(node1, spd_id)
IPsecUtil.vpp_ipsec_spd_add_if(node1, spd_id, interface1)
- IPsecUtil.vpp_ipsec_spd_add_entry(node1, spd_id, p_hi,
- PolicyAction.BYPASS, inbound=False,
- proto=proto)
- IPsecUtil.vpp_ipsec_spd_add_entry(node1, spd_id, p_hi,
- PolicyAction.BYPASS, inbound=True,
- proto=proto)
+ IPsecUtil.vpp_ipsec_policy_add(node1, spd_id, p_hi, PolicyAction.BYPASS,
+ inbound=False, proto=proto)
+ IPsecUtil.vpp_ipsec_policy_add(node1, spd_id, p_hi, PolicyAction.BYPASS,
+ inbound=True, proto=proto)
IPsecUtil.vpp_ipsec_add_spd(node2, spd_id)
IPsecUtil.vpp_ipsec_spd_add_if(node2, spd_id, interface2)
- IPsecUtil.vpp_ipsec_spd_add_entry(node2, spd_id, p_hi,
- PolicyAction.BYPASS, inbound=False,
- proto=proto)
- IPsecUtil.vpp_ipsec_spd_add_entry(node2, spd_id, p_hi,
- PolicyAction.BYPASS, inbound=True,
- proto=proto)
+ IPsecUtil.vpp_ipsec_policy_add(node2, spd_id, p_hi, PolicyAction.BYPASS,
+ inbound=False, proto=proto)
+ IPsecUtil.vpp_ipsec_policy_add(node2, spd_id, p_hi, PolicyAction.BYPASS,
+ inbound=True, proto=proto)
IPsecUtil.vpp_ipsec_add_sad_entries(node1, n_tunnels, sa_id_1, spi_1,
crypto_alg, crypto_key, integ_alg,