Add support for additional auth, encryption, PFS choices
Encryption algorithms: add AES CCM mode and AES GCM mode variants for 128/192/256 bit keys and 8/12/16 octet ICVs. In the API that will be 9 new choices for AES CCM and 9 for AES GCM, e.g. aes-256-ccm-16 (aes-{keysize}-ccm-{icv-size}). Add encrpytion algorithms for AES CTR mode: aes-128-ctr, aes-192-ctr, aes-256-ctr. Auth algorithms: add aes-xcbc and aes-cmac. PFS: add Diffie Hellman groups 15 to 31. Closes-Bug: #1938284 Depends-On: https://review.opendev.org/c/openstack/neutron-lib/+/903971 Change-Id: I07f49d8e91f0f16ee4c97e636ab3b62a5692d70c
This commit is contained in:
parent
256464aea6
commit
a5fc227751
|
@ -0,0 +1,80 @@
|
|||
# Copyright 2023 SysEleven GmbH
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
from neutron.db import migration
|
||||
import sqlalchemy as sa
|
||||
|
||||
"""add more ciphers
|
||||
|
||||
Revision ID: b18aab30fddc
|
||||
Revises: 22e0145ac80b
|
||||
Create Date: 2023-10-11 15:40:27.845720
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'b18aab30fddc'
|
||||
down_revision = '22e0145ac80b'
|
||||
|
||||
|
||||
AUTH_ALGORITHM_ENUM_VALUES = [
|
||||
'sha1', 'sha256', 'sha384', 'sha512',
|
||||
'aes-xcbc', 'aes-cmac',
|
||||
]
|
||||
|
||||
ENCRYPTION_ALGORITHM_ENUM_VALUES = [
|
||||
'3des',
|
||||
'aes-128', 'aes-192', 'aes-256',
|
||||
'aes-128-ctr', 'aes-192-ctr', 'aes-256-ctr',
|
||||
'aes-128-ccm-8', 'aes-192-ccm-8', 'aes-256-ccm-8',
|
||||
'aes-128-ccm-12', 'aes-192-ccm-12', 'aes-256-ccm-12',
|
||||
'aes-128-ccm-16', 'aes-192-ccm-16', 'aes-256-ccm-16',
|
||||
'aes-128-gcm-8', 'aes-192-gcm-8', 'aes-256-gcm-8',
|
||||
'aes-128-gcm-12', 'aes-192-gcm-12', 'aes-256-gcm-12',
|
||||
'aes-128-gcm-16', 'aes-192-gcm-16', 'aes-256-gcm-16',
|
||||
]
|
||||
|
||||
PFS_ENUM_VALUES = [
|
||||
'group2', 'group5', 'group14', 'group15',
|
||||
'group16', 'group17', 'group18', 'group19', 'group20', 'group21',
|
||||
'group22', 'group23', 'group24', 'group25', 'group26', 'group27',
|
||||
'group28', 'group29', 'group30', 'group31',
|
||||
]
|
||||
|
||||
|
||||
def upgrade():
|
||||
migration.alter_enum('ikepolicies', 'pfs',
|
||||
sa.Enum(*PFS_ENUM_VALUES, name="vpn_pfs"),
|
||||
nullable=False, do_drop=False)
|
||||
migration.alter_enum('ikepolicies', 'auth_algorithm',
|
||||
sa.Enum(*AUTH_ALGORITHM_ENUM_VALUES,
|
||||
name="vpn_auth_algorithms"),
|
||||
nullable=False, do_drop=False)
|
||||
migration.alter_enum('ikepolicies', 'encryption_algorithm',
|
||||
sa.Enum(*ENCRYPTION_ALGORITHM_ENUM_VALUES,
|
||||
name="vpn_encrypt_algorithms"),
|
||||
nullable=False, do_drop=False)
|
||||
|
||||
migration.alter_enum('ipsecpolicies', 'pfs',
|
||||
sa.Enum(*PFS_ENUM_VALUES, name="vpn_pfs"),
|
||||
nullable=False, do_rename=False, do_create=False)
|
||||
migration.alter_enum('ipsecpolicies', 'auth_algorithm',
|
||||
sa.Enum(*AUTH_ALGORITHM_ENUM_VALUES,
|
||||
name="vpn_auth_algorithms"),
|
||||
nullable=False, do_rename=False, do_create=False)
|
||||
migration.alter_enum('ipsecpolicies', 'encryption_algorithm',
|
||||
sa.Enum(*ENCRYPTION_ALGORITHM_ENUM_VALUES,
|
||||
name="vpn_encrypt_algorithms"),
|
||||
nullable=False, do_rename=False, do_create=False)
|
|
@ -1 +1 @@
|
|||
22e0145ac80b
|
||||
b18aab30fddc
|
||||
|
|
|
@ -24,6 +24,31 @@ from neutron.db import models_v2
|
|||
from neutron_vpnaas.services.vpn.common import constants
|
||||
|
||||
|
||||
AUTH_ALGORITHM_ENUM_VALUES = [
|
||||
'sha1', 'sha256', 'sha384', 'sha512',
|
||||
'aes-xcbc', 'aes-cmac',
|
||||
]
|
||||
|
||||
ENCRYPTION_ALGORITHM_ENUM_VALUES = [
|
||||
'3des',
|
||||
'aes-128', 'aes-192', 'aes-256',
|
||||
'aes-128-ctr', 'aes-192-ctr', 'aes-256-ctr',
|
||||
'aes-128-ccm-8', 'aes-192-ccm-8', 'aes-256-ccm-8',
|
||||
'aes-128-ccm-12', 'aes-192-ccm-12', 'aes-256-ccm-12',
|
||||
'aes-128-ccm-16', 'aes-192-ccm-16', 'aes-256-ccm-16',
|
||||
'aes-128-gcm-8', 'aes-192-gcm-8', 'aes-256-gcm-8',
|
||||
'aes-128-gcm-12', 'aes-192-gcm-12', 'aes-256-gcm-12',
|
||||
'aes-128-gcm-16', 'aes-192-gcm-16', 'aes-256-gcm-16',
|
||||
]
|
||||
|
||||
PFS_ENUM_VALUES = [
|
||||
'group2', 'group5', 'group14', 'group15',
|
||||
'group16', 'group17', 'group18', 'group19', 'group20', 'group21',
|
||||
'group22', 'group23', 'group24', 'group25', 'group26', 'group27',
|
||||
'group28', 'group29', 'group30', 'group31',
|
||||
]
|
||||
|
||||
|
||||
class IPsecPeerCidr(model_base.BASEV2):
|
||||
"""Internal representation of a IPsec Peer Cidrs."""
|
||||
|
||||
|
@ -43,12 +68,10 @@ class IPsecPolicy(model_base.BASEV2, model_base.HasId, model_base.HasProject):
|
|||
transform_protocol = sa.Column(sa.Enum("esp", "ah", "ah-esp",
|
||||
name="ipsec_transform_protocols"),
|
||||
nullable=False)
|
||||
auth_algorithm = sa.Column(sa.Enum("sha1", "sha256",
|
||||
"sha384", "sha512",
|
||||
auth_algorithm = sa.Column(sa.Enum(*AUTH_ALGORITHM_ENUM_VALUES,
|
||||
name="vpn_auth_algorithms"),
|
||||
nullable=False)
|
||||
encryption_algorithm = sa.Column(sa.Enum("3des", "aes-128",
|
||||
"aes-256", "aes-192",
|
||||
encryption_algorithm = sa.Column(sa.Enum(*ENCRYPTION_ALGORITHM_ENUM_VALUES,
|
||||
name="vpn_encrypt_algorithms"),
|
||||
nullable=False)
|
||||
encapsulation_mode = sa.Column(sa.Enum("tunnel", "transport",
|
||||
|
@ -58,8 +81,7 @@ class IPsecPolicy(model_base.BASEV2, model_base.HasId, model_base.HasProject):
|
|||
name="vpn_lifetime_units"),
|
||||
nullable=False)
|
||||
lifetime_value = sa.Column(sa.Integer, nullable=False)
|
||||
pfs = sa.Column(sa.Enum("group2", "group5", "group14",
|
||||
name="vpn_pfs"), nullable=False)
|
||||
pfs = sa.Column(sa.Enum(*PFS_ENUM_VALUES, name="vpn_pfs"), nullable=False)
|
||||
|
||||
|
||||
class IKEPolicy(model_base.BASEV2, model_base.HasId, model_base.HasProject):
|
||||
|
@ -67,12 +89,10 @@ class IKEPolicy(model_base.BASEV2, model_base.HasId, model_base.HasProject):
|
|||
__tablename__ = 'ikepolicies'
|
||||
name = sa.Column(sa.String(db_const.NAME_FIELD_SIZE))
|
||||
description = sa.Column(sa.String(db_const.DESCRIPTION_FIELD_SIZE))
|
||||
auth_algorithm = sa.Column(sa.Enum("sha1", "sha256",
|
||||
"sha384", "sha512",
|
||||
auth_algorithm = sa.Column(sa.Enum(*AUTH_ALGORITHM_ENUM_VALUES,
|
||||
name="vpn_auth_algorithms"),
|
||||
nullable=False)
|
||||
encryption_algorithm = sa.Column(sa.Enum("3des", "aes-128",
|
||||
"aes-256", "aes-192",
|
||||
encryption_algorithm = sa.Column(sa.Enum(*ENCRYPTION_ALGORITHM_ENUM_VALUES,
|
||||
name="vpn_encrypt_algorithms"),
|
||||
nullable=False)
|
||||
phase1_negotiation_mode = sa.Column(sa.Enum("main", 'aggressive',
|
||||
|
@ -84,8 +104,7 @@ class IKEPolicy(model_base.BASEV2, model_base.HasId, model_base.HasProject):
|
|||
lifetime_value = sa.Column(sa.Integer, nullable=False)
|
||||
ike_version = sa.Column(sa.Enum("v1", "v2", name="ike_versions"),
|
||||
nullable=False)
|
||||
pfs = sa.Column(sa.Enum("group2", "group5", "group14",
|
||||
name="vpn_pfs"), nullable=False)
|
||||
pfs = sa.Column(sa.Enum(*PFS_ENUM_VALUES, name="vpn_pfs"), nullable=False)
|
||||
|
||||
|
||||
class IPsecSiteConnection(model_base.BASEV2, model_base.HasId,
|
||||
|
|
|
@ -161,8 +161,12 @@ class BaseSwanProcess(object, metaclass=abc.ABCMeta):
|
|||
DIALECT_MAP = {
|
||||
"3des": "3des",
|
||||
"aes-128": "aes128",
|
||||
"aes-256": "aes256",
|
||||
"aes-192": "aes192",
|
||||
"aes-256": "aes256",
|
||||
"aes-ctr-128": "aesctr128",
|
||||
"aes-ctr-192": "aesctr192",
|
||||
"aes-ctr-256": "aesctr256",
|
||||
"aes-xcbc": "aes_xcbc",
|
||||
"sha256": "sha2_256",
|
||||
"sha384": "sha2_384",
|
||||
"sha512": "sha2_512",
|
||||
|
@ -170,6 +174,16 @@ class BaseSwanProcess(object, metaclass=abc.ABCMeta):
|
|||
"group5": "modp1536",
|
||||
"group14": "modp2048",
|
||||
"group15": "modp3072",
|
||||
"group16": "modp4096",
|
||||
"group17": "modp6144",
|
||||
"group18": "modp8192",
|
||||
"group19": "ecp256",
|
||||
"group20": "ecp384",
|
||||
"group21": "ecp521",
|
||||
"group22": "dh22",
|
||||
"group23": "dh23",
|
||||
"group24": "dh24",
|
||||
"group31": "curve25519",
|
||||
"bi-directional": "start",
|
||||
"response-only": "add",
|
||||
"v2": "insist",
|
||||
|
|
|
@ -76,9 +76,53 @@ class StrongSwanProcess(ipsec.BaseSwanProcess):
|
|||
STATUS_NOT_RUNNING_RE = 'Command:.*ipsec.*status.*Exit code: [1|3] '
|
||||
|
||||
def __init__(self, conf, process_id, vpnservice, namespace):
|
||||
self.DIALECT_MAP['v1'] = 'ikev1'
|
||||
self.DIALECT_MAP['v2'] = 'ikev2'
|
||||
self.DIALECT_MAP['sha256'] = 'sha256'
|
||||
dialect_map_update = {
|
||||
'v1': 'ikev1',
|
||||
'v2': 'ikev2',
|
||||
# ENCR_AES_CTR
|
||||
'aes-128-ctr': 'aes128ctr',
|
||||
'aes-192-ctr': 'aes192ctr',
|
||||
'aes-256-ctr': 'aes256ctr',
|
||||
# ENCR_AES_CCM_8
|
||||
'aes-128-ccm-8': 'aes128ccm8',
|
||||
'aes-192-ccm-8': 'aes192ccm8',
|
||||
'aes-256-ccm-8': 'aes256ccm8',
|
||||
# ENCR_AES_CCM_12
|
||||
'aes-128-ccm-12': 'aes128ccm12',
|
||||
'aes-192-ccm-12': 'aes192ccm12',
|
||||
'aes-256-ccm-12': 'aes256ccm12',
|
||||
# ENCR_AES_CCM_16
|
||||
'aes-128-ccm-16': 'aes128ccm16',
|
||||
'aes-192-ccm-16': 'aes192ccm16',
|
||||
'aes-256-ccm-16': 'aes256ccm16',
|
||||
# ENCR_AES_GCM_8
|
||||
'aes-128-gcm-8': 'aes128gcm8',
|
||||
'aes-192-gcm-8': 'aes192gcm8',
|
||||
'aes-256-gcm-8': 'aes256gcm8',
|
||||
# ENCR_AES_GCM_12
|
||||
'aes-128-gcm-12': 'aes128gcm12',
|
||||
'aes-192-gcm-12': 'aes192gcm12',
|
||||
'aes-256-gcm-12': 'aes256gcm12',
|
||||
# ENCR_AES_GCM_16
|
||||
'aes-128-gcm-16': 'aes128gcm16',
|
||||
'aes-192-gcm-16': 'aes192gcm16',
|
||||
'aes-256-gcm-16': 'aes256gcm16',
|
||||
# AUTH
|
||||
'sha256': 'sha256',
|
||||
'aes-xcbc': 'aesxcbc',
|
||||
'aes-cmac': 'aescmac',
|
||||
# PFS
|
||||
'group22': 'modp1024s160',
|
||||
'group23': 'modp2048s224',
|
||||
'group24': 'modp2048s256',
|
||||
'group25': 'ecp192',
|
||||
'group26': 'ecp224',
|
||||
'group27': 'ecp224bp',
|
||||
'group28': 'ecp256bp',
|
||||
'group29': 'ecp384bp',
|
||||
'group30': 'ecp512bp',
|
||||
}
|
||||
self.DIALECT_MAP.update(dialect_map_update)
|
||||
self._strongswan_piddir = self._get_strongswan_piddir()
|
||||
self._rootwrap_cfg = self._get_rootwrap_config()
|
||||
LOG.debug("strongswan piddir is '%s'", (self._strongswan_piddir))
|
||||
|
|
|
@ -61,7 +61,7 @@ conn {{ipsec_site_connection.id}}
|
|||
######################
|
||||
#ike version
|
||||
ikev2={{ipsec_site_connection.ikepolicy.ike_version}}
|
||||
# [encryption_algorithm]-[auth_algorithm]-[pfs]
|
||||
# [encryption_algorithm]-[auth_algorithm];[pfs]
|
||||
ike={{ipsec_site_connection.ikepolicy.encryption_algorithm}}-{{ipsec_site_connection.ikepolicy.auth_algorithm}};{{ipsec_site_connection.ikepolicy.pfs}}
|
||||
{% if ipsec_site_connection.ikepolicy.phase1_negotiation_mode == "aggressive" -%}
|
||||
aggressive=yes
|
||||
|
@ -76,10 +76,13 @@ conn {{ipsec_site_connection.id}}
|
|||
phase2={{ipsec_site_connection.ipsecpolicy.transform_protocol}}
|
||||
{% if ipsec_site_connection.ipsecpolicy.transform_protocol == "ah" -%}
|
||||
# AH protocol does not support encryption
|
||||
# [auth_algorithm]-[pfs]
|
||||
# [auth_algorithm];[pfs]
|
||||
phase2alg={{ipsec_site_connection.ipsecpolicy.auth_algorithm}};{{ipsec_site_connection.ipsecpolicy.pfs}}
|
||||
{% elif 'cm' in ipsec_site_connection.ipsecpolicy.encryption_algorithm -%}
|
||||
# [encryption_algorithm];[pfs]
|
||||
phase2alg={{ipsec_site_connection.ipsecpolicy.encryption_algorithm}};{{ipsec_site_connection.ipsecpolicy.pfs}}
|
||||
{% else -%}
|
||||
# [encryption_algorithm]-[auth_algorithm]-[pfs]
|
||||
# [encryption_algorithm]-[auth_algorithm];[pfs]
|
||||
phase2alg={{ipsec_site_connection.ipsecpolicy.encryption_algorithm}}-{{ipsec_site_connection.ipsecpolicy.auth_algorithm}};{{ipsec_site_connection.ipsecpolicy.pfs}}
|
||||
{% endif -%}
|
||||
# [encapsulation_mode]
|
||||
|
|
|
@ -28,6 +28,8 @@ conn {{ipsec_site_connection.id}}
|
|||
{%- endif %}
|
||||
{%- if ipsec_site_connection.ipsecpolicy.transform_protocol == "ah" %}
|
||||
ah={{ipsec_site_connection.ipsecpolicy.auth_algorithm}}-{{ipsec_site_connection.ipsecpolicy.pfs}}
|
||||
{%- elif 'cm' in ipsec_site_connection.ipsecpolicy.encryption_algorithm %}
|
||||
esp={{ipsec_site_connection.ipsecpolicy.encryption_algorithm}}-{{ipsec_site_connection.ipsecpolicy.pfs}}
|
||||
{%- else %}
|
||||
esp={{ipsec_site_connection.ipsecpolicy.encryption_algorithm}}-{{ipsec_site_connection.ipsecpolicy.auth_algorithm}}-{{ipsec_site_connection.ipsecpolicy.pfs}}
|
||||
{%- endif %}
|
||||
|
|
|
@ -515,6 +515,16 @@ class TestVpnaas(VPNPluginDbTestCase):
|
|||
with self.ikepolicy(name=name, description=description) as ikepolicy:
|
||||
self._check_policy(ikepolicy['ikepolicy'], keys, lifetime)
|
||||
|
||||
def test_create_ikepolicy_with_every_pfs(self):
|
||||
"""Test case to create ikepolicies with different pfs."""
|
||||
pfs_list = ['group2', 'group5', 'group14', 'group15', 'group16',
|
||||
'group17', 'group18', 'group19', 'group20', 'group21',
|
||||
'group22', 'group23', 'group24', 'group25', 'group26',
|
||||
'group27', 'group28', 'group29', 'group30', 'group31']
|
||||
name = "ikepolicy1"
|
||||
for group in pfs_list:
|
||||
self.ikepolicy(name=name, pfs=group, expected_res_status=201)
|
||||
|
||||
def test_create_ikepolicy_with_aggressive_mode(self):
|
||||
"""Test case to create an ikepolicy with aggressive mode."""
|
||||
name = "ikepolicy1"
|
||||
|
@ -748,6 +758,16 @@ class TestVpnaas(VPNPluginDbTestCase):
|
|||
description=description) as ipsecpolicy:
|
||||
self._check_policy(ipsecpolicy['ipsecpolicy'], keys, lifetime)
|
||||
|
||||
def test_create_ipsecpolicies_with_every_pfs(self):
|
||||
"""Test case to create ipsecpolicies with different pfs."""
|
||||
pfs_list = ['group2', 'group5', 'group14', 'group15', 'group16',
|
||||
'group17', 'group18', 'group19', 'group20', 'group21',
|
||||
'group22', 'group23', 'group24', 'group25', 'group26',
|
||||
'group27', 'group28', 'group29', 'group30', 'group31']
|
||||
name = "ipsecpolicy1"
|
||||
for group in pfs_list:
|
||||
self.ipsecpolicy(name=name, pfs=group, expected_res_status=201)
|
||||
|
||||
def test_delete_ipsecpolicy(self):
|
||||
"""Test case to delete an ipsecpolicy."""
|
||||
with self.ipsecpolicy(do_delete=False) as ipsecpolicy:
|
||||
|
|
|
@ -107,12 +107,12 @@ FAKE_VPN_SERVICE = {
|
|||
}
|
||||
|
||||
AUTH_ESP = '''esp
|
||||
# [encryption_algorithm]-[auth_algorithm]-[pfs]
|
||||
# [encryption_algorithm]-[auth_algorithm];[pfs]
|
||||
phase2alg=aes128-sha1;modp1536'''
|
||||
|
||||
AUTH_AH = '''ah
|
||||
# AH protocol does not support encryption
|
||||
# [auth_algorithm]-[pfs]
|
||||
# [auth_algorithm];[pfs]
|
||||
phase2alg=sha1;modp1536'''
|
||||
|
||||
OPENSWAN_CONNECTION_DETAILS = '''# rightsubnet=networkA/netmaskA, networkB/netmaskB (IKEv2 only)
|
||||
|
@ -131,7 +131,7 @@ OPENSWAN_CONNECTION_DETAILS = '''# rightsubnet=networkA/netmaskA, networkB/netma
|
|||
######################
|
||||
#ike version
|
||||
ikev2=never
|
||||
# [encryption_algorithm]-[auth_algorithm]-[pfs]
|
||||
# [encryption_algorithm]-[auth_algorithm];[pfs]
|
||||
ike=aes128-sha1;modp1536
|
||||
# [lifetime_value]
|
||||
ikelifetime=%(ike_lifetime)ss
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
prelude: >
|
||||
Support for AES CCM and GCM modes, AES-XCBC, AES-CMAC, and more DH groups
|
||||
features:
|
||||
- |
|
||||
Added support for more encryption algorithms (AES CCM and AES GCM modes),
|
||||
authentication algorithms (AES-XCBC, AES-CMAC) and PFS choices
|
||||
(Diffie Hellman groups 15 to 31).
|
Loading…
Reference in New Issue