aboutsummaryrefslogtreecommitdiffstats
path: root/resources/libraries/python
diff options
context:
space:
mode:
authorVratko Polak <vrpolak@cisco.com>2024-05-29 15:20:02 +0200
committerVratko Polak <vrpolak@cisco.com>2024-05-31 14:07:11 +0000
commit9c708c91e04540a6aa46a24b33d344181b58092c (patch)
tree7f9076a717d67d2d2e8363af37794cbb20e0899f /resources/libraries/python
parent7b335c86d80b2225e4ba7cd325ec8863adef8527 (diff)
feat(ipsec): Add suites for more algs
+ Add suite with UDP encap. + Add suite with anti replay enabled. + Add new enums where needed by the new suites. + Apply trimming in enum_util to support "3DES". + All 10ktnl suites written and tested. + New robot tags added. + Fix one comment from the parent. Change-Id: I2581814dbb327891d8658dd009c4e52ffd318e3b Signed-off-by: Vratko Polak <vrpolak@cisco.com> (cherry picked from commit b9dff484de0725bca3f65739519d952e3be55cbe)
Diffstat (limited to 'resources/libraries/python')
-rw-r--r--resources/libraries/python/IPsecUtil.py79
-rw-r--r--resources/libraries/python/enum_util.py19
2 files changed, 87 insertions, 11 deletions
diff --git a/resources/libraries/python/IPsecUtil.py b/resources/libraries/python/IPsecUtil.py
index 59374ab73f..1abfee2cec 100644
--- a/resources/libraries/python/IPsecUtil.py
+++ b/resources/libraries/python/IPsecUtil.py
@@ -85,13 +85,35 @@ class IpsecSpdAction(Enum):
class CryptoAlg(Enum):
- """Encryption algorithms."""
+ """Encryption algorithms.
+
+ API names and numeric enums from ipsec_types.api (enum ipsec_crypto_alg).
+
+ Lowercase names from ipsec_sa.h (foreach_ipsec_crypto_alg).
+
+ Scapy names are from:
+ https://github.com/secdev/scapy/blob/master/scapy/layers/ipsec.py
+
+ Key lengths from crypto.h
+ (foreach_crypto_cipher_alg and foreach_crypto_aead_alg).
+ """
NONE = ("none", 0, "none", 0)
AES_CBC_128 = ("aes-cbc-128", 1, "AES-CBC", 16)
+ AES_CBC_192 = ("aes-cbc-192", 2, "AES-CBC", 24)
AES_CBC_256 = ("aes-cbc-256", 3, "AES-CBC", 32)
+ AES_CTR_128 = ("aes-ctr-128", 4, "AES-CTR", 16)
+ AES_CTR_192 = ("aes-ctr-192", 5, "AES-CTR", 24)
+ AES_CTR_256 = ("aes-ctr-256", 6, "AES-CTR", 32)
AES_GCM_128 = ("aes-gcm-128", 7, "AES-GCM", 16)
+ AES_GCM_192 = ("aes-gcm-192", 8, "AES-GCM", 24)
AES_GCM_256 = ("aes-gcm-256", 9, "AES-GCM", 32)
+ DES_CBC = ("des-cbc", 10, "DES", 7)
+ _3DES_CBC = ("3des-cbc", 11, "3DES", 24)
+ CHACHA20_POLY1305 = ("chacha20-poly1305", 12, "CHACHA20-POLY1305", 32)
+ AES_NULL_GMAC_128 = ("aes-null-gmac-128", 13, "AES-NULL-GMAC", 16)
+ AES_NULL_GMAC_192 = ("aes-null-gmac-192", 14, "AES-NULL-GMAC", 24)
+ AES_NULL_GMAC_256 = ("aes-null-gmac-256", 15, "AES-NULL-GMAC", 32)
def __init__(
self, alg_name: str, alg_int_repr: int, scapy_name: str, key_len: int
@@ -108,10 +130,30 @@ class CryptoAlg(Enum):
class IntegAlg(Enum):
- """Integrity algorithm."""
+ """Integrity algorithms.
+
+ API names and numeric enums from ipsec_types.api (enum ipsec_integ_alg).
+
+ Lowercase names from ipsec_sa.h (foreach_ipsec_integ_alg).
+
+ Scapy names are from:
+ https://github.com/secdev/scapy/blob/master/scapy/layers/ipsec.py
+ Among those, "AES-CMAC-96" may be a mismatch,
+ but there is no sha2-related item with "96" in it.
+
+ Key lengths seem to be given double of digest length
+ from crypto.h (foreach_crypto_link_async_alg),
+ but data there is not complete
+ (e.g. it does not distinguish sha-256-96 from sha-256-128).
+ The missing values are chosen based on last number (e.g. 192 / 4 = 48).
+ """
NONE = ("none", 0, "none", 0)
+ MD5_96 = ("md5-96", 1, "HMAC-MD5-96", 24)
+ SHA1_96 = ("sha1-96", 2, "HMAC-SHA1-96", 24)
+ SHA_256_96 = ("sha-256-96", 3, "AES-CMAC-96", 24)
SHA_256_128 = ("sha-256-128", 4, "SHA2-256-128", 32)
+ SHA_384_192 = ("sha-384-192", 5, "SHA2-384-192", 48)
SHA_512_256 = ("sha-512-256", 6, "SHA2-512-256", 64)
def __init__(
@@ -1226,6 +1268,8 @@ class IPsecUtil:
addr_incr: int,
spi_d: dict,
existing_tunnels: int = 0,
+ udp_encap: bool = False,
+ anti_replay: bool = False,
) -> Tuple[List[bytes], List[bytes]]:
"""Create multiple IPsec tunnel interfaces on DUT1 node using PAPI.
@@ -1247,6 +1291,8 @@ class IPsecUtil:
:param addr_incr: IP / IPv6 address incremental step.
:param existing_tunnels: Number of tunnel interfaces before creation.
Useful mainly for reconf tests. Default 0.
+ :param udp_encap: Whether to apply UDP_ENCAP flag.
+ :param anti_replay: Whether to apply USE_ANTI_REPLAY flag.
:type nodes: dict
:type tun_ips: dict
:type if1_key: str
@@ -1258,6 +1304,8 @@ class IPsecUtil:
:type addr_incr: int
:type spi_d: dict
:type existing_tunnels: int
+ :type udp_encap: bool
+ :type anti_replay: bool
:returns: Generated ckeys and ikeys.
:rtype: List[bytes], List[bytes]
"""
@@ -1331,6 +1379,10 @@ class IPsecUtil:
c_key = dict(length=0, data=None)
i_key = dict(length=0, data=None)
common_flags = IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
+ if udp_encap:
+ common_flags |= IPsecSadFlags.IPSEC_API_SAD_FLAG_UDP_ENCAP
+ if anti_replay:
+ common_flags |= IPsecSadFlags.IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY
sad_entry = dict(
sad_id=None,
spi=None,
@@ -1470,6 +1522,8 @@ class IPsecUtil:
addr_incr: int,
spi_d: dict,
existing_tunnels: int = 0,
+ udp_encap: bool = False,
+ anti_replay: bool = False,
) -> None:
"""Create multiple IPsec tunnel interfaces on DUT2 node using PAPI.
@@ -1493,6 +1547,8 @@ class IPsecUtil:
:param addr_incr: IP / IPv6 address incremental step.
:param existing_tunnels: Number of tunnel interfaces before creation.
Useful mainly for reconf tests. Default 0.
+ :param udp_encap: Whether to apply UDP_ENCAP flag.
+ :param anti_replay: Whether to apply USE_ANTI_REPLAY flag.
:type nodes: dict
:type tun_ips: dict
:type if2_key: str
@@ -1505,6 +1561,8 @@ class IPsecUtil:
:type addr_incr: int
:type spi_d: dict
:type existing_tunnels: int
+ :type udp_encap: bool
+ :type anti_replay: bool
"""
crypto_alg = get_enum_instance(CryptoAlg, crypto_alg)
integ_alg = get_enum_instance(IntegAlg, integ_alg)
@@ -1569,6 +1627,10 @@ class IPsecUtil:
c_key = dict(length=0, data=None)
i_key = dict(length=0, data=None)
common_flags = IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
+ if udp_encap:
+ common_flags |= IPsecSadFlags.IPSEC_API_SAD_FLAG_UDP_ENCAP
+ if anti_replay:
+ common_flags |= IPsecSadFlags.IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY
sad_entry = dict(
sad_id=None,
spi=None,
@@ -1718,6 +1780,8 @@ class IPsecUtil:
raddr_ip2: str,
raddr_range: int,
existing_tunnels: int = 0,
+ udp_encap: bool = False,
+ anti_replay: bool = False,
return_keys: bool = False,
) -> Optional[Tuple[List[bytes], List[bytes], int, int]]:
"""Create multiple IPsec tunnel interfaces between two VPP nodes.
@@ -1747,6 +1811,8 @@ class IPsecUtil:
:param existing_tunnels: Number of tunnel interfaces before creation.
Useful mainly for reconf tests. Default 0.
:param return_keys: Whether generated keys should be returned.
+ :param udp_encap: Whether to apply UDP_ENCAP flag.
+ :param anti_replay: Whether to apply USE_ANTI_REPLAY flag.
:type nodes: dict
:type tun_if1_ip_addr: str
:type tun_if2_ip_addr: str
@@ -1760,6 +1826,8 @@ class IPsecUtil:
:type raddr_range: int
:type existing_tunnels: int
:type return_keys: bool
+ :type udp_encap: bool
+ :type anti_replay: bool
:returns: Ckeys, ikeys, spi_1, spi_2.
:rtype: Optional[Tuple[List[bytes], List[bytes], int, int]]
"""
@@ -1791,6 +1859,8 @@ class IPsecUtil:
addr_incr,
spi_d,
existing_tunnels,
+ udp_encap,
+ anti_replay,
)
if "DUT2" in nodes.keys():
IPsecUtil._ipsec_create_tunnel_interfaces_dut2_papi(
@@ -1806,6 +1876,8 @@ class IPsecUtil:
addr_incr,
spi_d,
existing_tunnels,
+ udp_encap,
+ anti_replay,
)
if return_keys:
@@ -2150,7 +2222,8 @@ class IPsecUtil:
# The proto argument does not correspond to IPsecProto.
# The allowed values come from src/vnet/ip/protocols.def
# and we do not have a good enum for that yet.
- # FlowUti. and FlowUtil. are close but not exactly the same.
+ # FlowUtil.FlowType and FlowUtil.FlowProto are close,
+ # but not exactly the same.
# TODO: to be fixed to use full PAPI when it is ready in VPP
cmd = (
diff --git a/resources/libraries/python/enum_util.py b/resources/libraries/python/enum_util.py
index 41dfd8a459..f721936ee4 100644
--- a/resources/libraries/python/enum_util.py
+++ b/resources/libraries/python/enum_util.py
@@ -31,13 +31,15 @@ def get_enum_instance(
to convert string into the corresponding Enum instance.
Aliases are also recognized.
- As an added benefit, support various Robot-like niceties,
- like lower case, or dash or space instead of underscore.
-
As a common shortcut, value is returned it it already is an instance.
Another convenience: None or empty string is processed as "NONE".
+ As an added benefit, support various Robot-like niceties,
+ like lower case, or dash or space instead of underscore.
+ Also strip the identifiers, this is mostly due to "3DES".
+ Enum instance cannot start with a number, so "_3DES" + strip is needed.
+
If the class is a subclass of IntEnum, int values
and (string) values convertable to int are also accepted as input.
@@ -59,9 +61,10 @@ def get_enum_instance(
return value
if not value:
value = "NONE"
- normalized_name = str(value).upper().replace("-", "_").replace(" ", "_")
+ normalized_name = str(value).upper().replace("-", " ").replace("_", " ")
members = enum_class.__members__ # Includes aliases, useful for NONE.
- if normalized_name not in members:
- msg = f"Enum class {enum_class} does not have value {normalized_name!r}"
- raise ValueError(msg)
- return members[normalized_name]
+ for member_name in members:
+ if normalized_name.strip() == member_name.replace("_", " ").strip():
+ return members[member_name]
+ msg = f"Enum class {enum_class} does not have value {normalized_name!r}"
+ raise ValueError(msg)