diff options
author | Christian Poessinger <christian@poessinger.com> | 2021-07-26 21:54:54 +0200 |
---|---|---|
committer | Christian Poessinger <christian@poessinger.com> | 2021-07-26 21:54:54 +0200 |
commit | c31488f0e3206c4477692065781e49f2fbd7c9ed (patch) | |
tree | a73bd86a2d59ab3b19700f36935336708cf2b91f | |
parent | 67a5ca7fa372f8e3679b533d370ffa362c76f4ca (diff) | |
download | vyos-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.tmpl | 20 | ||||
-rwxr-xr-x | src/op_mode/ikev2_profile_generator.py | 104 |
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.') |