summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Poessinger <christian@poessinger.com>2021-07-26 21:54:54 +0200
committerChristian Poessinger <christian@poessinger.com>2021-07-26 21:54:54 +0200
commitc31488f0e3206c4477692065781e49f2fbd7c9ed (patch)
treea73bd86a2d59ab3b19700f36935336708cf2b91f
parent67a5ca7fa372f8e3679b533d370ffa362c76f4ca (diff)
downloadvyos-1x-c31488f0e3206c4477692065781e49f2fbd7c9ed.tar.gz
vyos-1x-c31488f0e3206c4477692065781e49f2fbd7c9ed.zip
ipsec: T1210: extend support for iOS profile generation
$ generate ipsec mac-ios-profile <connection> remote <ip>
-rw-r--r--data/templates/ipsec/ios_profile.tmpl20
-rwxr-xr-xsrc/op_mode/ikev2_profile_generator.py104
2 files changed, 107 insertions, 17 deletions
diff --git a/data/templates/ipsec/ios_profile.tmpl b/data/templates/ipsec/ios_profile.tmpl
index 49e8b0992..af6c79d6e 100644
--- a/data/templates/ipsec/ios_profile.tmpl
+++ b/data/templates/ipsec/ios_profile.tmpl
@@ -58,35 +58,29 @@
<!-- The client uses EAP to authenticate -->
<key>ExtendedAuthEnabled</key>
<integer>1</integer>
-{% if ike_proposal is defined and ike_proposal is not none %}
<!-- The next two dictionaries are optional (as are the keys in them), but it is recommended to specify them as the default is to use 3DES.
IMPORTANT: Because only one proposal is sent (even if nothing is configured here) it must match the server configuration -->
<key>IKESecurityAssociationParameters</key>
-{% for ike, ike_config in ike_proposal.items() %}
<dict>
<!-- @see https://developer.apple.com/documentation/networkextension/nevpnikev2encryptionalgorithm -->
<key>EncryptionAlgorithm</key>
- <string>{{ ike_config.encryption | upper }}</string>
+ <string>{{ ike_encryption.encryption }}</string>
<!-- @see https://developer.apple.com/documentation/networkextension/nevpnikev2integrityalgorithm -->
<key>IntegrityAlgorithm</key>
- <string>{{ ike_config.hash | upper }}</string>
+ <string>{{ ike_encryption.hash }}</string>
<!-- @see https://developer.apple.com/documentation/networkextension/nevpnikev2diffiehellmangroup -->
<key>DiffieHellmanGroup</key>
- <integer>{{ ike_config.dh_group | upper }}
+ <integer>{{ ike_encryption.dh_group }}</integer>
</dict>
-{% endfor %}
-{% endif %}
-{% if esp_proposal is defined and esp_proposal is not none %}
<key>ChildSecurityAssociationParameters</key>
-{% for esp, esp_config in esp_proposal.items() %}
<dict>
<key>EncryptionAlgorithm</key>
- <string>{{ esp_config.encryption | upper }}</string>
+ <string>{{ esp_encryption.encryption }}</string>
<key>IntegrityAlgorithm</key>
- <string>{{ esp_config.hash | upper }}</string>
+ <string>{{ esp_encryption.hash }}</string>
+ <key>DiffieHellmanGroup</key>
+ <integer>{{ ike_encryption.dh_group }}</integer>
</dict>
-{% endfor %}
-{% endif %}
</dict>
</dict>
<!-- This payload is optional but it provides an easy way to install the CA certificate together with the configuration -->
diff --git a/src/op_mode/ikev2_profile_generator.py b/src/op_mode/ikev2_profile_generator.py
index 4ff37341c..ce93ec057 100755
--- a/src/op_mode/ikev2_profile_generator.py
+++ b/src/op_mode/ikev2_profile_generator.py
@@ -19,11 +19,12 @@ import argparse
from jinja2 import Template
from sys import exit
from socket import getfqdn
+from cryptography.x509.oid import NameOID
from vyos.config import Config
-from vyos.template import render_to_string
-from cryptography.x509.oid import NameOID
from vyos.pki import load_certificate
+from vyos.template import render_to_string
+from vyos.util import ask_input
parser = argparse.ArgumentParser()
parser.add_argument("--connection", action="store", help="IPsec IKEv2 remote-access connection name from CLI", required=True)
@@ -73,7 +74,102 @@ data['ca_cn'] = ca_cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)[0].v
data['cert_cn'] = cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value
data['ca_cert'] = conf.return_value(pki_base + ['ca', ca_name, 'certificate'])
-data['esp_proposal'] = conf.get_config_dict(ipsec_base + ['esp-group', data['esp_group'], 'proposal'], key_mangling=('-', '_'), get_first_key=True)
-data['ike_proposal'] = conf.get_config_dict(ipsec_base + ['ike-group', data['ike_group'], 'proposal'], key_mangling=('-', '_'), get_first_key=True)
+# Apple profiles only support one IKE/ESP encryption cipher and hash, whereas
+# VyOS comes with a multitude of different proposals for a connection.
+#
+# We take all available proposals from the VyOS CLI and ask the user which one
+# he would like to get enabled in his profile - thus there is limited possibility
+# to select a proposal that is not supported on the connection profile.
+#
+# IOS supports IKE-SA encryption algorithms:
+# - DES
+# - 3DES
+# - AES-128
+# - AES-256
+# - AES-128-GCM
+# - AES-256-GCM
+# - ChaCha20Poly1305
+#
+vyos2apple_cipher = {
+ '3des' : '3DES',
+ 'aes128' : 'AES-128',
+ 'aes256' : 'AES-256',
+ 'aes128gcm128' : 'AES-128-GCM',
+ 'aes256gcm128' : 'AES-256-GCM',
+ 'chacha20poly1305' : 'ChaCha20Poly1305',
+}
+
+# IOS supports IKE-SA integrity algorithms:
+# - SHA1-96
+# - SHA1-160
+# - SHA2-256
+# - SHA2-384
+# - SHA2-512
+#
+vyos2apple_integrity = {
+ 'sha1' : 'SHA1-96',
+ 'sha1_160' : 'SHA1-160',
+ 'sha256' : 'SHA2-256',
+ 'sha384' : 'SHA2-384',
+ 'sha512' : 'SHA2-512',
+}
+
+# IOS 14.2 and later do no support dh-group 1,2 and 5. Supported DH groups would
+# be: 14, 15, 16, 17, 18, 19, 20, 21, 31
+supported_dh_groups = ['14', '15', '16', '17', '18', '19', '20', '21', '31']
+
+esp_proposals = conf.get_config_dict(ipsec_base + ['esp-group', data['esp_group'], 'proposal'],
+ key_mangling=('-', '_'), get_first_key=True)
+ike_proposal = conf.get_config_dict(ipsec_base + ['ike-group', data['ike_group'], 'proposal'],
+ key_mangling=('-', '_'), get_first_key=True)
+
+# Create a dictionary containing Apple conform IKE settings
+ike = {}
+count = 1
+for _, proposal in ike_proposal.items():
+ if {'dh_group', 'encryption', 'hash'} <= set(proposal):
+ if (proposal['encryption'] in set(vyos2apple_cipher) and
+ proposal['hash'] in set(vyos2apple_integrity) and
+ proposal['dh_group'] in set(supported_dh_groups)):
+
+ # We 're-code' from the VyOS IPSec proposals to the Apple naming scheme
+ proposal['encryption'] = vyos2apple_cipher[ proposal['encryption'] ]
+ proposal['hash'] = vyos2apple_integrity[ proposal['hash'] ]
+
+ ike.update( { str(count) : proposal } )
+ count += 1
+
+# Create a dictionary containing Apple conform ESP settings
+esp = {}
+count = 1
+for _, proposal in esp_proposals.items():
+ if {'encryption', 'hash'} <= set(proposal):
+ if proposal['encryption'] in set(vyos2apple_cipher) and proposal['hash'] in set(vyos2apple_integrity):
+ # We 're-code' from the VyOS IPSec proposals to the Apple naming scheme
+ proposal['encryption'] = vyos2apple_cipher[ proposal['encryption'] ]
+ proposal['hash'] = vyos2apple_integrity[ proposal['hash'] ]
+
+ esp.update( { str(count) : proposal } )
+ count += 1
+try:
+ # Propare the input questions for the user
+ tmp = '\n'
+ for number, options in ike.items():
+ tmp += f'({number}) Encryption {options["encryption"]}, Integrity {options["hash"]}, DH group {options["dh_group"]}\n'
+ tmp += '\nSelect one of the above IKE groups: '
+ data['ike_encryption'] = ike[ ask_input(tmp, valid_responses=list(ike)) ]
+
+ tmp = '\n'
+ for number, options in esp.items():
+ tmp += f'({number}) Encryption {options["encryption"]}, Integrity {options["hash"]}\n'
+ tmp += '\nSelect one of the above ESP groups: '
+ data['esp_encryption'] = esp[ ask_input(tmp, valid_responses=list(esp)) ]
+
+
+except KeyboardInterrupt:
+ exit("Interrupted")
+print('\n\n==== <snip> ====')
print(render_to_string('ipsec/ios_profile.tmpl', data))
+print('==== </snip> ====\n')
+print('Save the XML from above to a new file named "vyos.mobileconfig" and E-Mail it to your phone.')