summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2024-06-09 14:39:45 +0200
committerMergify <37929162+mergify[bot]@users.noreply.github.com>2024-06-10 08:28:55 +0000
commit4485aa56a8bc5e37a1ecc7caaab10eeb354c76ab (patch)
tree51091ca54b87ff0161d8f4de74f6b50c394f7202
parent2d98f3b17e1146db6362e302d28474fb6f5520e6 (diff)
downloadvyos-1x-4485aa56a8bc5e37a1ecc7caaab10eeb354c76ab.tar.gz
vyos-1x-4485aa56a8bc5e37a1ecc7caaab10eeb354c76ab.zip
op-mode: T6424: ipsec: honor certificate CN and CA chain during profile generation
In e6fe6e50a5c ("op-mode: ipsec: T6407: fix profile generation") we fixed support for multiple CAs when dealing with the generation of Apple IOS profiles. This commit extends support to properly include the common name of the server certificate issuer and all it's paren't CAs. A list of parent CAs is automatically generated from the "PKI" subsystem content and embedded into the resulting profile. (cherry picked from commit d65f43589612c30dfaa5ce30aca5b8b48bf73211)
-rw-r--r--data/templates/ipsec/ios_profile.j218
-rw-r--r--python/vyos/template.py13
-rwxr-xr-xsrc/op_mode/ikev2_profile_generator.py32
3 files changed, 37 insertions, 26 deletions
diff --git a/data/templates/ipsec/ios_profile.j2 b/data/templates/ipsec/ios_profile.j2
index a9ae1c7a9..935acbf8e 100644
--- a/data/templates/ipsec/ios_profile.j2
+++ b/data/templates/ipsec/ios_profile.j2
@@ -48,10 +48,10 @@
<!-- Optional, if it matches the CN of the root CA certificate (not the full subject DN) a certificate request will be sent
NOTE: If this is not configured make sure to configure leftsendcert=always on the server, otherwise it won't send its certificate -->
<key>ServerCertificateIssuerCommonName</key>
- <string>{{ ca_cn }}</string>
+ <string>{{ ca_common_name }}</string>
<!-- Optional, the CN or one of the subjectAltNames of the server certificate to verify it, if not set RemoteIdentifier will be used -->
<key>ServerCertificateCommonName</key>
- <string>{{ cert_cn }}</string>
+ <string>{{ cert_common_name }}</string>
<!-- The server is authenticated using a certificate -->
<key>AuthenticationMethod</key>
<string>Certificate</string>
@@ -83,24 +83,22 @@
</dict>
</dict>
</dict>
-{% if certs is vyos_defined %}
+{% if ca_certificates is vyos_defined %}
<!-- This payload is optional but it provides an easy way to install the CA certificate together with the configuration -->
-{% for cert in certs %}
- <!-- Payload for: {{ cert.ca_cn }} -->
+{% for ca in ca_certificates %}
+ <!-- Payload for: {{ ca.ca_name }} -->
<dict>
<key>PayloadIdentifier</key>
- <string>org.{{ cert.ca_cn | lower | replace(' ', '.') | replace('_', '.') }}</string>
+ <string>org.{{ ca.ca_name | lower | replace(' ', '.') | replace('_', '.') }}</string>
<key>PayloadUUID</key>
- <string>{{ cert.ca_cn | generate_uuid4 }}</string>
+ <string>{{ ca.ca_name | get_uuid }}</string>
<key>PayloadType</key>
<string>com.apple.security.root</string>
<key>PayloadVersion</key>
<integer>1</integer>
<!-- This is the Base64 (PEM) encoded CA certificate -->
<key>PayloadContent</key>
- <data>
- {{ cert.ca_cert }}
- </data>
+ <data>{{ ca.ca_chain }}</data>
</dict>
{% endfor %}
{% endif %}
diff --git a/python/vyos/template.py b/python/vyos/template.py
index cdcbdc6c3..a4fff649c 100644
--- a/python/vyos/template.py
+++ b/python/vyos/template.py
@@ -523,10 +523,17 @@ def get_esp_ike_cipher(group_config, ike_group=None):
return ciphers
@register_filter('get_uuid')
-def get_uuid(interface):
+def get_uuid(seed):
""" Get interface IP addresses"""
- from uuid import uuid1
- return uuid1()
+ if seed:
+ from hashlib import md5
+ from uuid import UUID
+ tmp = md5()
+ tmp.update(seed.encode('utf-8'))
+ return str(UUID(tmp.hexdigest()))
+ else:
+ from uuid import uuid1
+ return uuid1()
openvpn_translate = {
'des': 'des-cbc',
diff --git a/src/op_mode/ikev2_profile_generator.py b/src/op_mode/ikev2_profile_generator.py
index 4ac4fb14a..b55fdeab2 100755
--- a/src/op_mode/ikev2_profile_generator.py
+++ b/src/op_mode/ikev2_profile_generator.py
@@ -21,6 +21,10 @@ from socket import getfqdn
from cryptography.x509.oid import NameOID
from vyos.configquery import ConfigTreeQuery
+from vyos.pki import CERT_BEGIN
+from vyos.pki import CERT_END
+from vyos.pki import find_chain
+from vyos.pki import encode_certificate
from vyos.pki import load_certificate
from vyos.template import render_to_string
from vyos.utils.io import ask_input
@@ -146,27 +150,29 @@ data['rfqdn'] = '.'.join(tmp)
pki = conf.get_config_dict(pki_base, get_first_key=True)
cert_name = data['authentication']['x509']['certificate']
-data['certs'] = []
+cert_data = load_certificate(pki['certificate'][cert_name]['certificate'])
+data['cert_common_name'] = cert_data.subject.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value
+data['ca_common_name'] = cert_data.issuer.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value
+data['ca_certificates'] = []
-for ca_name in data['authentication']['x509']['ca_certificate']:
- tmp = {}
- ca_cert = load_certificate(pki['ca'][ca_name]['certificate'])
- cert = load_certificate(pki['certificate'][cert_name]['certificate'])
-
-
- tmp['ca_cn'] = ca_cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value
- tmp['cert_cn'] = cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value
- tmp['ca_cert'] = conf.value(pki_base + ['ca', ca_name, 'certificate'])
-
- data['certs'].append(tmp)
+loaded_ca_certs = {load_certificate(c['certificate'])
+ for c in pki['ca'].values()} if 'ca' in pki else {}
+for ca_name in data['authentication']['x509']['ca_certificate']:
+ loaded_ca_cert = load_certificate(pki['ca'][ca_name]['certificate'])
+ ca_full_chain = find_chain(loaded_ca_cert, loaded_ca_certs)
+ for ca in ca_full_chain:
+ tmp = {
+ 'ca_name' : ca.subject.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value,
+ 'ca_chain' : encode_certificate(ca).replace(CERT_BEGIN, '').replace(CERT_END, '').replace('\n', ''),
+ }
+ data['ca_certificates'].append(tmp)
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)
-
# This script works only for Apple iOS/iPadOS and Windows. Both operating systems
# have different limitations thus we load the limitations based on the operating
# system used.