diff options
author | Vratko Polak <vrpolak@cisco.com> | 2024-05-29 15:20:02 +0200 |
---|---|---|
committer | Vratko Polak <vrpolak@cisco.com> | 2024-05-31 14:06:48 +0000 |
commit | d26edc6d9bbc4112a91d294eccc570cbb87af693 (patch) | |
tree | effe5921ed1f03c597304fd0a67a759b3cf34c7f /resources/libraries/python | |
parent | dc85c836d1615923def23f77c734c082d63df6df (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 da8033a0b40e7a45d449597bb7141dffa6ef94ef)
Diffstat (limited to 'resources/libraries/python')
-rw-r--r-- | resources/libraries/python/IPsecUtil.py | 79 | ||||
-rw-r--r-- | resources/libraries/python/enum_util.py | 19 |
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) |