diff --git a/config.cfg b/config.cfg
index f103a70..4a73c03 100644
--- a/config.cfg
+++ b/config.cfg
@@ -4,6 +4,7 @@
# Every device must have a unique username.
# You can generate up to 250 users at one time.
# Usernames with leading 0's or containing only numbers should be escaped in double quotes, e.g. "000dan" or "123".
+# Emails are not allowed
users:
- phone
- laptop
diff --git a/roles/strongswan/defaults/main.yml b/roles/strongswan/defaults/main.yml
index a9d71a2..3a2a6f1 100644
--- a/roles/strongswan/defaults/main.yml
+++ b/roles/strongswan/defaults/main.yml
@@ -10,9 +10,25 @@ algo_ondemand_wifi_exclude: '_null'
algo_dns_adblocking: false
ipv6_support: false
dns_encryption: true
-domain: false
-subjectAltName_IP: "{{ 'DNS:' if IP_subject_alt_name|regex_search('[a-z]') else 'IP:' }}{{ IP_subject_alt_name }}"
-subjectAltName_USER: "{% if '@' in item %}email:{{ item }}{% else %}DNS:{{ item }}{% endif %}"
+openssl_constraint_random_id: "{{ IP_subject_alt_name | to_uuid }}.algo"
+subjectAltName_type: "{{ 'DNS' if IP_subject_alt_name|regex_search('[a-z]') else 'IP' }}"
+subjectAltName: >-
+ {{ subjectAltName_type }}:{{ IP_subject_alt_name }}
+ {%- if ipv6_support -%},IP:{{ ansible_default_ipv6['address'] }}{%- endif -%}
+subjectAltName_USER: "email:{{ item }}@{{ openssl_constraint_random_id }}"
+nameConstraints: >-
+ critical,permitted;{{ subjectAltName_type }}:{{ IP_subject_alt_name }}{{- '/255.255.255.255' if subjectAltName_type == 'IP' else '' -}}
+ {%- if subjectAltName_type == 'IP' -%}
+ ,permitted;DNS:{{ openssl_constraint_random_id }}
+ {%- else -%}
+ ,excluded;IP:0.0.0.0/0.0.0.0
+ {%- endif -%}
+ ,permitted;email:{{ openssl_constraint_random_id }}
+ {%- if ipv6_support -%}
+ ,permitted;IP:{{ ansible_default_ipv6['address'] }}/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+ {%- else -%}
+ ,excluded;IP:0:0:0:0:0:0:0:0/0:0:0:0:0:0:0:0
+ {%- endif -%}
openssl_bin: openssl
strongswan_enabled_plugins:
- aes
diff --git a/roles/strongswan/tasks/openssl.yml b/roles/strongswan/tasks/openssl.yml
index feb627f..c7e193f 100644
--- a/roles/strongswan/tasks/openssl.yml
+++ b/roles/strongswan/tasks/openssl.yml
@@ -1,13 +1,5 @@
---
- block:
- - name: Set subjectAltName as a fact
- set_fact:
- subjectAltName: >-
- {{ subjectAltName_IP }}
- {%- if ipv6_support -%},IP:{{ ansible_default_ipv6['address'] }}{%- endif -%}
- {%- if domain and subjectAltName_DNS -%},DNS:{{ subjectAltName_DNS }}{%- endif -%}
- tags: always
-
- debug: var=subjectAltName
- name: Ensure the pki directory does not exist
@@ -132,6 +124,30 @@
executable: bash
with_items: "{{ users }}"
+ - name: Build the tests pair
+ shell: >
+ umask 077;
+ {{ openssl_bin }} req -utf8 -new
+ -newkey ec:ecparams/secp384r1.pem
+ -config <(cat openssl.cnf <(printf "[basic_exts]\nsubjectAltName=DNS:google-algo-test-pair.com"))
+ -keyout private/google-algo-test-pair.com.key
+ -out reqs/google-algo-test-pair.com.req -nodes
+ -passin pass:"{{ CA_password }}"
+ -subj "/CN=google-algo-test-pair.com" -batch &&
+ {{ openssl_bin }} ca -utf8
+ -in reqs/google-algo-test-pair.com.req
+ -out certs/google-algo-test-pair.com.crt
+ -config <(cat openssl.cnf <(printf "[basic_exts]\nsubjectAltName=DNS:google-algo-test-pair.com"))
+ -days 3650 -batch
+ -passin pass:"{{ CA_password }}"
+ -subj "/CN=google-algo-test-pair.com" &&
+ touch certs/google-algo-test-pair.com_crt_generated
+ args:
+ chdir: "{{ ipsec_pki_path }}"
+ creates: certs/google-algo-test-pair.com_crt_generated
+ executable: bash
+ when: tests|default(false)|bool
+
- name: Build openssh public keys
openssl_publickey:
path: "{{ ipsec_pki_path }}/public/{{ item }}.pub"
@@ -201,7 +217,7 @@
chdir: "{{ ipsec_pki_path }}"
creates: crl/{{ item }}.crt
executable: bash
- when: item not in users
+ when: item.split('@')[0] not in users
with_items: "{{ valid_certs.stdout_lines }}"
- name: Genereate new CRL file
diff --git a/roles/strongswan/templates/charon.conf.j2 b/roles/strongswan/templates/charon.conf.j2
index 303c92f..e8aab6a 100644
--- a/roles/strongswan/templates/charon.conf.j2
+++ b/roles/strongswan/templates/charon.conf.j2
@@ -358,7 +358,7 @@ charon {
x509 {
# Discard certificates with unsupported or unknown critical extensions.
- # enforce_critical = yes
+ enforce_critical = no
}
diff --git a/roles/strongswan/templates/mobileconfig.j2 b/roles/strongswan/templates/mobileconfig.j2
index 807683f..8405f8e 100644
--- a/roles/strongswan/templates/mobileconfig.j2
+++ b/roles/strongswan/templates/mobileconfig.j2
@@ -93,7 +93,7 @@
1440
LocalIdentifier
- {{ item.0 }}
+ {{ item.0 }}@{{ openssl_constraint_random_id }}
PayloadCertificateUUID
{{ pkcs12_PayloadCertificateUUID }}
CertificateType
diff --git a/roles/strongswan/templates/openssl.cnf.j2 b/roles/strongswan/templates/openssl.cnf.j2
index d4cff0c..fa22017 100644
--- a/roles/strongswan/templates/openssl.cnf.j2
+++ b/roles/strongswan/templates/openssl.cnf.j2
@@ -119,9 +119,9 @@ keyUsage = digitalSignature, keyEncipherment
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always
-# This could be marked critical, but it's nice to support reading by any
-# broken clients who attempt to do so.
-basicConstraints = CA:true
+basicConstraints = critical,CA:true,pathlen:0
+nameConstraints = {{ nameConstraints }}
+
# Limit key usage to CA tasks. If you really want to use the generated pair as
# a self-signed cert, comment this out.
diff --git a/tests/ipsec-client.sh b/tests/ipsec-client.sh
index c64ca53..b5d4958 100755
--- a/tests/ipsec-client.sh
+++ b/tests/ipsec-client.sh
@@ -4,6 +4,16 @@ set -euxo pipefail
xmllint --noout ./configs/10.0.8.100/ipsec/apple/user1.mobileconfig
+CA_CONSTRAINTS="$(openssl verify -verbose \
+ -CAfile ./configs/10.0.8.100/ipsec/.pki/cacert.pem \
+ ./configs/10.0.8.100/ipsec/.pki/certs/google-algo-test-pair.com.crt 2>&1)" || true
+
+echo "$CA_CONSTRAINTS" | grep "permitted subtree violation" >/dev/null && \
+ echo "Name Constraints test passed" || \
+ (echo "Name Constraints test failed" && exit 1)
+
+echo "$CA_CONSTRAINTS"
+
ansible-playbook deploy_client.yml \
-e client_ip=localhost \
-e vpn_user=desktop \