]> git.ipfire.org Git - people/ms/network.git/blobdiff - src/functions/functions.vpn-security-policies
security-policies: Add function to generate ESP proposal for strongswan
[people/ms/network.git] / src / functions / functions.vpn-security-policies
index e70684838850e57bbb3d03ec52d1f5955cf112ca..eb4b915678c02b075b49d0a59d2a7cc3e31570ee 100644 (file)
 VPN_SECURITY_POLICIES_CONFIG_SETTINGS="CIPHER COMPRESSION GROUP_TYPE INTEGRITY KEY_EXCHANGE LIFETIME PFS"
 VPN_SECURITY_POLICIES_READONLY="system"
 
-VPN_SUPPORTED_CIPHERS="AES192 AES256 AES512"
-VPN_SUPPORTED_INTEGRITY="SHA512 SHA256 SHA128"
-VPN_SUPPORTED_GROUP_TYPES="MODP8192 MODP4096"
+VPN_DEFAULT_SECURITY_POLICY="system"
+
+declare -A VPN_SUPPORTED_CIPHERS=(
+       # 3DES-CBC
+       [3DES-CBC]="168 bit 3DES-EDE-CBC"
+
+       # AES-CBC
+       [AES256-CBC]="256 bit AES-CBC"
+       [AES192-CBC]="192 bit AES-CBC"
+       [AES128-CBC]="128 bit AES-CBC"
+
+       # AES-CTR
+       [AES256-CTR]="256 bit AES-COUNTER"
+       [AES192-CTR]="192 bit AES-COUNTER"
+       [AES128-CTR]="128 bit AES-COUNTER"
+
+       # AES-GCM
+       [AES256-GCM128]="256 bit AES-GCM with 128 bit ICV"
+       [AES192-GCM128]="192 bit AES-GCM with 128 bit ICV"
+       [AES128-GCM128]="128 bit AES-GCM with 128 bit ICV"
+       [AES256-GCM96]="256 bit AES-GCM with 96 bit ICV"
+       [AES192-GCM96]="192 bit AES-GCM with 96 bit ICV"
+       [AES128-GCM96]="128 bit AES-GCM with 96 bit ICV"
+       [AES256-GCM64]="256 bit AES-GCM with 64 bit ICV"
+       [AES192-GCM64]="192 bit AES-GCM with 64 bit ICV"
+       [AES128-GCM64]="128 bit AES-GCM with 64 bit ICV"
+
+       # AES-CCM
+       [AES256-CCM128]="256 bit AES-CCM with 128 bit ICV"
+       [AES192-CCM128]="192 bit AES-CCM with 128 bit ICV"
+       [AES128-CCM128]="128 bit AES-CCM with 128 bit ICV"
+       [AES256-CCM96]="256 bit AES-CCM with 96 bit ICV"
+       [AES192-CCM96]="192 bit AES-CCM with 96 bit ICV"
+       [AES128-CCM96]="128 bit AES-CCM with 96 bit ICV"
+       [AES256-CCM64]="256 bit AES-CCM with 64 bit ICV"
+       [AES192-CCM64]="192 bit AES-CCM with 64 bit ICV"
+       [AES128-CCM64]="128 bit AES-CCM with 64 bit ICV"
+
+       # CAMELLIA-CBC
+       [CAMELLIA256-CBC]="256 bit CAMELLIA-CBC"
+       [CAMELLIA192-CBC]="192 bit CAMELLIA-CBC"
+       [CAMELLIA128-CBC]="128 bit CAMELLIA-CBC"
+
+       # CAMELLIA-CTR
+       [CAMELLIA256-CTR]="256 bit CAMELLIA-COUNTER"
+       [CAMELLIA192-CTR]="192 bit CAMELLIA-COUNTER"
+       [CAMELLIA128-CTR]="128 bit CAMELLIA-COUNTER"
+
+       # CAMELLIA-GCM
+       [CAMELLIA256-GCM128]="256 bit CAMELLIA-GCM with 128 bit ICV"
+       [CAMELLIA192-GCM128]="192 bit CAMELLIA-GCM with 128 bit ICV"
+       [CAMELLIA128-GCM128]="128 bit CAMELLIA-GCM with 128 bit ICV"
+       [CAMELLIA256-GCM96]="256 bit CAMELLIA-GCM with 96 bit ICV"
+       [CAMELLIA192-GCM96]="192 bit CAMELLIA-GCM with 96 bit ICV"
+       [CAMELLIA128-GCM96]="128 bit CAMELLIA-GCM with 96 bit ICV"
+       [CAMELLIA256-GCM64]="256 bit CAMELLIA-GCM with 64 bit ICV"
+       [CAMELLIA192-GCM64]="192 bit CAMELLIA-GCM with 64 bit ICV"
+       [CAMELLIA128-GCM64]="128 bit CAMELLIA-GCM with 64 bit ICV"
+
+       # CAMELLIA-CCM
+       [CAMELLIA256-CCM128]="256 bit CAMELLIA-CCM with 128 bit ICV"
+       [CAMELLIA192-CCM128]="192 bit CAMELLIA-CCM with 128 bit ICV"
+       [CAMELLIA128-CCM128]="128 bit CAMELLIA-CCM with 128 bit ICV"
+       [CAMELLIA256-CCM96]="256 bit CAMELLIA-CCM with 96 bit ICV"
+       [CAMELLIA192-CCM96]="192 bit CAMELLIA-CCM with 96 bit ICV"
+       [CAMELLIA128-CCM96]="128 bit CAMELLIA-CCM with 96 bit ICV"
+       [CAMELLIA256-CCM64]="256 bit CAMELLIA-CCM with 64 bit ICV"
+       [CAMELLIA192-CCM64]="192 bit CAMELLIA-CCM with 64 bit ICV"
+       [CAMELLIA128-CCM64]="128 bit CAMELLIA-CCM with 64 bit ICV"
+)
+
+declare -A CIPHER_TO_STRONGSWAN=(
+       # 3DES-CBC
+       [3DES-CBC]="3des"
+
+       # AES-CBC
+       [AES256-CBC]="aes256"
+       [AES192-CBC]="aes192"
+       [AES128-CBC]="aes128"
+
+       # AES-CTR
+       [AES256-CTR]="aes256ctr"
+       [AES192-CTR]="aes192ctr"
+       [AES128-CTR]="aes128ctr"
+
+       # AES-GCM
+       [AES256-GCM128]="aes256gcm128"
+       [AES192-GCM128]="aes192gcm128"
+       [AES128-GCM128]="aes128gcm128"
+       [AES256-GCM96]="aes256gcm96"
+       [AES192-GCM96]="aes192gcm96"
+       [AES128-GCM96]="aes128gcm96"
+       [AES256-GCM64]="aes256gcm64"
+       [AES192-GCM64]="aes192gcm64"
+       [AES128-GCM64]="aes128gcm64"
+
+       # AES-CCM
+       [AES256-CCM128]="aes256ccm128"
+       [AES192-CCM128]="aes192ccm128"
+       [AES128-CCM128]="aes128ccm128"
+       [AES256-CCM96]="aes256ccm96"
+       [AES192-CCM96]="aes192ccm96"
+       [AES128-CCM96]="aes128ccm96"
+       [AES256-CCM64]="aes256ccm64"
+       [AES192-CCM64]="aes192ccm64"
+       [AES128-CCM64]="aes128ccm64"
+
+       # CAMELLIA-CBC
+       [CAMELLIA256-CBC]="camellia256"
+       [CAMELLIA192-CBC]="camellia192"
+       [CAMELLIA128-CBC]="camellia128"
+
+       # CAMELLIA-CTR
+       [CAMELLIA256-CTR]="camellia256ctr"
+       [CAMELLIA192-CTR]="camellia192ctr"
+       [CAMELLIA128-CTR]="camellia128ctr"
+
+       # CAMELLIA-GCM
+       [CAMELLIA256-GCM128]="camellia256gcm128"
+       [CAMELLIA192-GCM128]="camellia192gcm128"
+       [CAMELLIA128-GCM128]="camellia128gcm128"
+       [CAMELLIA256-GCM96]="camellia256gcm96"
+       [CAMELLIA192-GCM96]="camellia192gcm96"
+       [CAMELLIA128-GCM96]="camellia128gcm96"
+       [CAMELLIA256-GCM64]="camellia256gcm64"
+       [CAMELLIA192-GCM64]="camellia192gcm64"
+       [CAMELLIA128-GCM64]="camellia128gcm64"
+
+       # CAMELLIA-CCM
+       [CAMELLIA256-CCM128]="camellia256ccm128"
+       [CAMELLIA192-CCM128]="camellia192ccm128"
+       [CAMELLIA128-CCM128]="camellia128ccm128"
+       [CAMELLIA256-CCM96]="camellia256ccm96"
+       [CAMELLIA192-CCM96]="camellia192ccm96"
+       [CAMELLIA128-CCM96]="camellia128ccm96"
+       [CAMELLIA256-CCM64]="camellia256ccm64"
+       [CAMELLIA192-CCM64]="camellia192ccm64"
+       [CAMELLIA128-CCM64]="camellia128ccm64"
+)
+
+declare -A VPN_SUPPORTED_INTEGRITY=(
+       [MD5]="MD5-HMAC"
+
+       # SHA
+       [SHA1]="SHA1-HMAC"
+       [SHA512]="512 bit SHA2-HMAC"
+       [SHA384]="384 bit SHA2-HMAC"
+       [SHA256]="256 bit SHA2-HMAC"
+
+       # AES
+       [AES-XCBC]="AES-XCBC"
+       [AES-CMAC]="AES-CMAC"
+       [AES256-GMAC]="256 bit AES-GMAC"
+       [AES192-GMAC]="192 bit AES-GMAC"
+       [AES128-GMAC]="128 bit AES-GMAC"
+)
+
+declare -A INTEGRITY_TO_STRONGSWAN=(
+       [MD5]="md5"
+
+       # SHA
+       [SHA1]="sha1"
+       [SHA512]="sha512"
+       [SHA384]="sha384"
+       [SHA256]="sha256"
+
+       # AES
+       [AES-XCBC]="aesxcbc"
+       [AES-CMAC]="aescmac"
+       [AES256-GMAC]="aes256gmac"
+       [AES192-GMAC]="aes192gmac"
+       [AES128-GMAC]="aes128gmac"
+)
+
+declare -A VPN_SUPPORTED_GROUP_TYPES=(
+       # Regular Groups
+       [MODP768]="768 bit Modulo Prime Group"
+       [MODP1024]="1024 bit Modulo Prime Group"
+       [MODP1536]="1536 bit Modulo Prime Group"
+       [MODP2048]="2048 bit Modulo Prime Group"
+       [MODP3072]="3072 bit Modulo Prime Group"
+       [MODP4096]="4096 bit Modulo Prime Group"
+       [MODP6144]="6144 bit Modulo Prime Group"
+       [MODP8192]="8192 bit Modulo Prime Group"
+
+       # NIST Elliptic Curve Groups
+       [ECP192]="192 bit NIST Elliptic Curve Group"
+       [ECP224]="224 bit NIST Elliptic Curve Group"
+       [ECP256]="256 bit NIST Elliptic Curve Group"
+       [ECP384]="384 bit NIST Elliptic Curve Group"
+       [ECP521]="521 bit NIST Elliptic Curve Group"
+
+       # Brainpool Elliptic Curve Groups
+       [ECP224BP]="224 bit Brainpool Elliptic Curve Group"
+       [ECP256BP]="256 bit Brainpool Elliptic Curve Group"
+       [ECP384BP]="384 bit Brainpool Elliptic Curve Group"
+       [ECP512BP]="512 bit Brainpool Elliptic Curve Group"
+
+       # Curve25519
+       [CURVE25519]="256 bit Elliptic Curve 25519"
+)
+
+declare -A GROUP_TYPE_TO_STRONGSWAN=(
+       # Regular Groups
+       [MODP768]="modp768"
+       [MODP1024]="modp1024"
+       [MODP1536]="modp1536"
+       [MODP2048]="modp2048"
+       [MODP3072]="modp3072"
+       [MODP4096]="modp4096"
+       [MODP6144]="modp6144"
+       [MODP8192]="modp8192"
+
+       # NIST Elliptic Curve Groups
+       [ECP192]="ecp192"
+       [ECP224]="ecp224"
+       [ECP256]="ecp256"
+       [ECP384]="ecp384"
+       [ECP521]="ecp521"
+
+       # Brainpool Elliptic Curve Groups
+       [ECP224BP]="ecp224bp"
+       [ECP256BP]="ecp256bp"
+       [ECP384BP]="ecp384bp"
+       [ECP512BP]="ecp512bp"
+
+       # Curve25519
+       [CURVE25519]="curve25519"
+)
 
 # This functions checks if a policy is readonly
 # returns true when yes and false when no
@@ -158,15 +384,24 @@ vpn_security_policies_show() {
        # This could be done in a loop but a loop is much more complicated
        # because we print 'Group Types' but the variable is named 'GROUP_TYPES'
        cli_print_fmt1 1 "Ciphers:"
-       cli_print_fmt1 2 "${CIPHER}"
+       local cipher
+       for cipher in ${CIPHER}; do
+               cli_print_fmt1 2 "${VPN_SUPPORTED_CIPHERS[${cipher}]-${cipher}}"
+       done
        cli_space
 
        cli_print_fmt1 1 "Integrity:"
-       cli_print_fmt1 2 "${INTEGRITY}"
+       local integrity
+       for integrity in ${INTEGRITY}; do
+               cli_print_fmt1 2 "${VPN_SUPPORTED_INTEGRITY[${integrity}]-${integrity}}"
+       done
        cli_space
 
        cli_print_fmt1 1 "Group Types:"
-       cli_print_fmt1 2 "${GROUP_TYPE}"
+       local group_type
+       for group_type in ${GROUP_TYPE}; do
+               cli_print_fmt1 2 "${VPN_SUPPORTED_GROUP_TYPES[${group_type}]-${group_type}}"
+       done
        cli_space
 
        cli_print_fmt1 1 "Key Exchange:" "${KEY_EXCHANGE}"
@@ -242,7 +477,7 @@ vpn_security_policies_cipher(){
                        +*)
                                value=${1#+}
                                # Check if the Ciphers is in the list of supported ciphers.
-                               if ! isoneof value ${VPN_SUPPORTED_CIPHERS}; then
+                               if ! isoneof value ${!VPN_SUPPORTED_CIPHERS[@]}; then
                                        # We do not break here because this error does not break the processing of the next maybe valid values.
                                        log ERROR "${value} is not a supported cipher and can thats why not added to the list of ciphers."
                                else
@@ -322,7 +557,7 @@ vpn_security_policies_group_type(){
                        +*)
                                value=${1#+}
                                # Check if the group type is in the list of supported group types.
-                               if ! isoneof value ${VPN_SUPPORTED_GROUP_TYPES}; then
+                               if ! isoneof value ${!VPN_SUPPORTED_GROUP_TYPES[@]}; then
                                        # We do not break here because the processing of other maybe valid values are indepent from this error.
                                        log ERROR "${value} is not a supported group type and can thats why not added to the list of group types."
                                else
@@ -382,7 +617,7 @@ vpn_security_policies_integrity(){
                        +*)
                                value=${1#+}
                                # Check if the Ciphers is in the list of supported integrity hashes.
-                               if ! isoneof value ${VPN_SUPPORTED_INTEGRITY}; then
+                               if ! isoneof value ${!VPN_SUPPORTED_INTEGRITY[@]}; then
                                        # We do not break here because the processing of other maybe valid values are indepent from this error.
                                        log ERROR "${value} is not a supported integrity hash and can thats why not added to the list of integrity hashes."
                                else
@@ -517,14 +752,24 @@ vpn_security_policies_new() {
                return ${EXIT_ERROR}
        fi
 
+       # Check if our source policy exists
+       if ! vpn_security_policy_exists "${VPN_DEFAULT_SECURITY_POLICY}"; then
+               error "Default VPN Security Policy '${VPN_DEFAULT_SECURITY_POLICY}' does not exist"
+               return ${EXIT_ERROR}
+       fi
+
        log DEBUG "Creating VPN Security Policy ${name}"
 
-       if copy "$(vpn_security_policies_path "system")" "$(vpn_security_policies_path ${name})"; then
+       if copy "$(vpn_security_policies_path "${VPN_DEFAULT_SECURITY_POLICY}")"
+                       "$(vpn_security_policies_path ${name})"; then
                log INFO "VPN Security Policy ${name} successfully created"
        else
                log ERROR "Could not create VPN Security Policy ${name}"
                return ${EXIT_ERROR}
        fi
+
+       # Show the newly created policy
+       vpn_security_policies_show "${name}"
 }
 
 # Function that deletes based on the passed parameters one ore more vpn security policies
@@ -545,3 +790,123 @@ vpn_security_policies_destroy() {
                settings_remove $(vpn_security_policies_path ${name})
        done
 }
+
+vpn_security_policies_cipher_is_aead() {
+       local cipher=${1}
+
+       # All CCM and GCM ciphers are AEAD
+       string_match "[CG]CM" "${cipher}"
+}
+
+vpn_security_policies_make_ah_proposal() {
+       local name=${1}
+
+       # Read the config settings
+       local ${VPN_SECURITY_POLICIES_CONFIG_SETTINGS}
+       if ! vpn_security_policies_read_config "${name}"; then
+               return ${EXIT_ERROR}
+       fi
+
+       local proposals
+
+       local cipher
+       for cipher in ${CIPHER}; do
+               # Translate cipher
+               local _cipher=${CIPHER_TO_STRONGSWAN[${cipher}]}
+
+               if ! isset _cipher; then
+                       log WARN "Unsupported cipher: ${cipher}"
+                       continue
+               fi
+
+               local integrity
+               for integrity in ${INTEGRITY}; do
+                       local _integrity=${INTEGRITY_TO_STRONGSWAN[${integrity}]}
+
+                       if ! isset _integrity; then
+                               log WARN "Unsupported integrity: ${integrity}"
+                               continue
+                       fi
+
+                       local group_type
+                       for group_type in ${GROUP_TYPE}; do
+                               local _group_type=${GROUP_TYPE_TO_STRONGSWAN[${group_type}]}
+
+                               if ! isset _group_type; then
+                                       log WARN "Unsupported group-type: ${group_type}"
+                                       continue
+                               fi
+
+                               # Put everything together
+                               list_append proposals "${_cipher}-${_integrity}-${_group_type}"
+                       done
+               done
+       done
+
+       # Returns as a comma-separated list
+       list_join proposals ,
+}
+
+vpn_security_policies_make_esp_proposal() {
+       local name=${1}
+
+       # Read the config settings
+       local ${VPN_SECURITY_POLICIES_CONFIG_SETTINGS}
+       if ! vpn_security_policies_read_config "${name}"; then
+               return ${EXIT_ERROR}
+       fi
+
+       local proposals
+
+       local cipher
+       for cipher in ${CIPHER}; do
+               # Translate cipher
+               local _cipher=${CIPHER_TO_STRONGSWAN[${cipher}]}
+
+               if ! isset _cipher; then
+                       log WARN "Unsupported cipher: ${cipher}"
+                       continue
+               fi
+
+               if vpn_security_policies_cipher_is_aead ${cipher}; then
+                       local group_type
+                       for group_type in ${GROUP_TYPE}; do
+                               local _group_type=${GROUP_TYPE_TO_STRONGSWAN[${group_type}]}
+
+                               if ! isset _group_type; then
+                                       log WARN "Unsupported group-type: ${group_type}"
+                                       continue
+                               fi
+
+                               # Put everything together
+                               list_append proposals "${_cipher}-${_group_type}"
+                       done
+               else
+                       local integrity
+                       for integrity in ${INTEGRITY}; do
+                               local _integrity=${INTEGRITY_TO_STRONGSWAN[${integrity}]}
+
+                               if ! isset _integrity; then
+                                       log WARN "Unsupported integrity: ${integrity}"
+                                       continue
+                               fi
+
+                               local group_type
+                               for group_type in ${GROUP_TYPE}; do
+                                       local _group_type=${GROUP_TYPE_TO_STRONGSWAN[${group_type}]}
+
+                                       if ! isset _group_type; then
+                                               log WARN "Unsupported group-type: ${group_type}"
+                                               continue
+                                       fi
+
+                                       # Put everything together
+                                       list_append proposals "${_cipher}-${_integrity}-${_group_type}"
+                               done
+                       done
+               fi
+       done
+
+       # Returns as a comma-separated list
+       list_join proposals ,
+}