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 \