X-Git-Url: http://git.ipfire.org/?p=people%2Fms%2Fnetwork.git;a=blobdiff_plain;f=src%2Ffunctions%2Ffunctions.vpn-security-policies;h=138e8210e12096dc696ba3c47287dac2acf330fe;hp=eb4b915678c02b075b49d0a59d2a7cc3e31570ee;hb=HEAD;hpb=0d64549787ceca0e5f687e51c64817e3e12b77c9 diff --git a/src/functions/functions.vpn-security-policies b/src/functions/functions.vpn-security-policies index eb4b9156..138e8210 100644 --- a/src/functions/functions.vpn-security-policies +++ b/src/functions/functions.vpn-security-policies @@ -19,8 +19,9 @@ # # ############################################################################### -VPN_SECURITY_POLICIES_CONFIG_SETTINGS="CIPHER COMPRESSION GROUP_TYPE INTEGRITY KEY_EXCHANGE LIFETIME PFS" -VPN_SECURITY_POLICIES_READONLY="system" +VPN_SECURITY_POLICIES_CONFIG_SETTINGS="CIPHERS COMPRESSION GROUP_TYPES \ + INTEGRITIES PSEUDO_RANDOM_FUNCTIONS KEY_EXCHANGE LIFETIME PFS" +VPN_SECURITY_POLICIES_READONLY="system performance" VPN_DEFAULT_SECURITY_POLICY="system" @@ -91,6 +92,12 @@ declare -A VPN_SUPPORTED_CIPHERS=( [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" + + # DJB + [CHACHA20-POLY1305]="256 bit ChaCha20/Poly1305 with 128 bit ICV" + + # No Encryption + [NULL]="No Encryption" ) declare -A CIPHER_TO_STRONGSWAN=( @@ -160,9 +167,43 @@ declare -A CIPHER_TO_STRONGSWAN=( [CAMELLIA256-CCM64]="camellia256ccm64" [CAMELLIA192-CCM64]="camellia192ccm64" [CAMELLIA128-CCM64]="camellia128ccm64" + + # DJB + [CHACHA20-POLY1305]="chacha20poly1305" + + # No Encryption + [NULL]="null" +) + +declare -A VPN_SUPPORTED_PSEUDO_RANDOM_FUNCTIONS=( + [MD5]="MD5" + + # SHA + [SHA1]="SHA1" + [SHA256]="SHA256" + [SHA384]="SHA384" + [SHA512]="SHA512" + + # AES + [AES-XCBC]="AES-XCBC" + [AES-CMAC]="AES-CMAC" +) + +declare -A PSEUDO_RANDOM_FUNCTION_TO_STRONGSWAN=( + [MD5]="prfmd5" + + # SHA + [SHA1]="prfsha1" + [SHA256]="prfsha256" + [SHA384]="prfsha384" + [SHA512]="prfsha512" + + # AES + [AES-XCBC]="prfaesxcbc" + [AES-CMAC]="prfaescmac" ) -declare -A VPN_SUPPORTED_INTEGRITY=( +declare -A VPN_SUPPORTED_INTEGRITIES=( [MD5]="MD5-HMAC" # SHA @@ -222,6 +263,9 @@ declare -A VPN_SUPPORTED_GROUP_TYPES=( # Curve25519 [CURVE25519]="256 bit Elliptic Curve 25519" + + # Curve448 + [CURVE448]="224 bit Elliptic Curve 448" ) declare -A GROUP_TYPE_TO_STRONGSWAN=( @@ -248,10 +292,59 @@ declare -A GROUP_TYPE_TO_STRONGSWAN=( [ECP384BP]="ecp384bp" [ECP512BP]="ecp512bp" - # Curve25519 + # More Curves [CURVE25519]="curve25519" + [CURVE448]="curve448" ) +cli_vpn_security_policies() { + local action + local security_policy + + if vpn_security_policy_exists ${1}; then + security_policy=${1} + key=${2} + shift 2 + + case "${key}" in + ciphers|compression|integrities|lifetime|pfs|show) + vpn_security_policies_${key} ${security_policy} "$@" + ;; + pseudo-random-functions) + vpn_security_policies_pseudo_random_functions "${security_policy}" "$@" + ;; + group-types) + vpn_security_policies_group_types ${security_policy} "$@" + ;; + key-exchange) + vpn_security_policies_key_exchange ${security_policy} "$@" + ;; + *) + error "Unrecognized argument: ${key}" + exit ${EXIT_ERROR} + ;; + esac + else + action=${1} + shift + + case "${action}" in + new) + vpn_security_policies_new "$@" + ;; + destroy) + vpn_security_policies_destroy "$@" + ;; + ""|*) + if [ -n "${action}" ]; then + error "Unrecognized argument: '${action}'" + fi + exit ${EXIT_ERROR} + ;; + esac + fi +} + # This functions checks if a policy is readonly # returns true when yes and false when no vpn_security_policies_check_readonly() { @@ -289,7 +382,32 @@ vpn_security_policies_write_config() { return ${EXIT_ERROR} fi - # TODO everytime we successfully write a config we should call some trigger to take the changes into effect + if ! vpn_security_policies_reload ${name}; then + log WARNING "Could not reload the IPsec connection using this security policy" + return ${EXIT_ERROR} + fi +} + +# reload IPsec connections using a special policy +vpn_security_policies_reload() { + local name=${1} + + local connection + for connection in $(ipsec_list_connections); do + local SECURITY_POLICY ENABLED + + if ! ipsec_connection_read_config "${connection}" "SECURITY_POLICY"; then + continue + fi + + if [[ "${SECURITY_POLICY}" = "${name}" ]] && enabled ENABLED; then + if ! ipsec_connection_to_strongswan "${connection}"; then + log ERROR "Could not generate strongswan config for ${connnection}" + fi + fi + done + + ipsec_strongswan_load } # This funtion writes the value for one key to a via ${name} specificated vpn security policy configuration file @@ -343,7 +461,7 @@ vpn_security_policies_read_config() { if [ $# -eq 0 ] && [ -n "${VPN_SECURITY_POLICIES_CONFIG_SETTINGS}" ]; then list_append args ${VPN_SECURITY_POLICIES_CONFIG_SETTINGS} else - list_append args $@ + list_append args "$@" fi local path="$(vpn_security_policies_path ${name})" @@ -385,21 +503,28 @@ vpn_security_policies_show() { # because we print 'Group Types' but the variable is named 'GROUP_TYPES' cli_print_fmt1 1 "Ciphers:" local cipher - for cipher in ${CIPHER}; do + for cipher in ${CIPHERS}; do cli_print_fmt1 2 "${VPN_SUPPORTED_CIPHERS[${cipher}]-${cipher}}" done cli_space cli_print_fmt1 1 "Integrity:" local integrity - for integrity in ${INTEGRITY}; do - cli_print_fmt1 2 "${VPN_SUPPORTED_INTEGRITY[${integrity}]-${integrity}}" + for integrity in ${INTEGRITIES}; do + cli_print_fmt1 2 "${VPN_SUPPORTED_INTEGRITIES[${integrity}]-${integrity}}" + done + cli_space + + cli_print_fmt1 1 "Pseudo Random Functions:" + local prf + for prf in ${PSEUDO_RANDOM_FUNCTIONS}; do + cli_print_fmt1 2 "${VPN_SUPPORTED_PSEUDO_RANDOM_FUNCTIONS[${prf}]-${prf}}" done cli_space cli_print_fmt1 1 "Group Types:" local group_type - for group_type in ${GROUP_TYPE}; do + for group_type in ${GROUP_TYPES}; do cli_print_fmt1 2 "${VPN_SUPPORTED_GROUP_TYPES[${group_type}]-${group_type}}" done cli_space @@ -444,7 +569,7 @@ vpn_security_policy_exists() { # This function parses the parameters for the 'cipher' command -vpn_security_policies_cipher(){ +vpn_security_policies_ciphers() { local name=${1} shift @@ -453,54 +578,95 @@ vpn_security_policies_cipher(){ return ${EXIT_ERROR} fi - local CIPHER - if ! vpn_security_policies_read_config ${name} "CIPHER"; then + local CIPHERS + if ! vpn_security_policies_read_config ${name} "CIPHERS"; then return ${EXIT_ERROR} fi # Remove duplicated entries to proceed the list safely - CIPHER="$(list_unique ${CIPHER})" + CIPHERS="$(list_unique ${CIPHERS})" + + local ciphers_added + local ciphers_removed + local ciphers_set while [ $# -gt 0 ]; do - case "${1}" in + local arg="${1}" + + case "${arg}" in + +*) + list_append ciphers_added "${arg:1}" + ;; -*) - value=${1#-} - # Check if the cipher is in the list of ciphers and - # check if the list has after removing this cipher at least one valid value - if list_match ${value} ${CIPHER}; then - list_remove CIPHER ${value} - else - # We do not break here because this error does not break the processing of the next maybe valid values. - log ERROR "Can not remove ${value} from the list of Ciphers because ${value} is not in the list." - fi + list_append ciphers_removed "${arg:1}" ;; - +*) - value=${1#+} - # Check if the Ciphers is in the list of supported ciphers. - 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 - if list_match ${value} ${CIPHER}; then - log WARNING "${value} is already in the list of ciphers of this policy." - else - list_append CIPHER ${value} - fi - fi + [A-Z0-9]*) + list_append ciphers_set "${arg}" + ;; + *) + error "Invalid argument: ${arg}" + return ${EXIT_ERROR} ;; esac shift done - # Check if the list contain at least one valid cipher - if [ $(list_length ${CIPHER}) -ge 1 ]; then - if ! vpn_security_policies_write_config_key ${name} "CIPHER" ${CIPHER}; then - log ERROR "The changes for the vpn security policy ${name} could not be written." - fi + # Check if the user is trying a mixed operation + if ! list_is_empty ciphers_set && (! list_is_empty ciphers_added || ! list_is_empty ciphers_removed); then + error "You cannot reset the cipher list and add or remove ciphers at the same time" + return ${EXIT_ERROR} + fi + + # Set new cipher list + if ! list_is_empty ciphers_set; then + # Check if all ciphers are valid + local cipher + for cipher in ${ciphers_set}; do + if ! vpn_security_policies_cipher_supported ${cipher}; then + error "Unsupported cipher: ${cipher}" + return ${EXIT_ERROR} + fi + done + + CIPHERS="${ciphers_set}" + + # Perform incremental updates else - log ERROR "After proceding all ciphers the list is empty and thats why no changes are written." + local cipher + + # Perform all removals + for cipher in ${ciphers_removed}; do + if ! list_remove CIPHERS ${cipher}; then + warning "${cipher} was not on the list and could not be removed" + fi + done + + for cipher in ${ciphers_added}; do + if vpn_security_policies_cipher_supported ${cipher}; then + if ! list_append_unique CIPHERS ${cipher}; then + warning "${cipher} is already on the cipher list" + fi + else + warning "${cipher} is unknown or unsupported and could not be added" + fi + done + fi + + # Check if the list contain at least one valid cipher + if list_is_empty CIPHERS; then + error "Cannot save an empty cipher list" return ${EXIT_ERROR} fi + + # Save everything + if ! vpn_security_policies_write_config_key ${name} "CIPHERS" ${CIPHERS}; then + log ERROR "The changes for the vpn security policy ${name} could not be written." + fi + + cli_headline 1 "Current cipher list for ${name}:" + for cipher in ${CIPHERS}; do + cli_print_fmt1 1 "${cipher}" "${VPN_SUPPORTED_CIPHERS[${cipher}]}" + done } # This function parses the parameters for the 'compression' command @@ -524,7 +690,7 @@ vpn_security_policies_compression(){ } # This function parses the parameters for the 'group-type' command -vpn_security_policies_group_type(){ +vpn_security_policies_group_types() { local name=${1} shift @@ -533,114 +699,297 @@ vpn_security_policies_group_type(){ return ${EXIT_ERROR} fi - local GROUP_TYPE - if ! vpn_security_policies_read_config ${name} "GROUP_TYPE"; then + local GROUP_TYPES + if ! vpn_security_policies_read_config ${name} "GROUP_TYPES"; then return ${EXIT_ERROR} fi # Remove duplicated entries to proceed the list safely - GROUP_TYPE="$(list_unique ${GROUP_TYPE})" + GROUP_TYPES="$(list_unique ${GROUP_TYPES})" + + local group_types_added + local group_types_removed + local group_types_set while [ $# -gt 0 ]; do - case "${1}" in + local arg="${1}" + + case "${arg}" in + +*) + list_append group_types_added "${arg:1}" + ;; -*) - value=${1#-} - # Check if the group type is in the list of group types and - # check if the list has after removing this group type at leatst one valid value - if list_match ${value} ${GROUP_TYPE}; then - list_remove GROUP_TYPE ${value} - else - # We do not break here because this error does not break the processing of the next maybe valid values. - log ERROR "Can not remove ${value} from the list of group types because ${value} is not in the list." - fi + list_append group_types_removed "${arg:1}" ;; - +*) - value=${1#+} - # Check if the group type is in the list of supported group types. - 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 - if list_match ${value} ${GROUP_TYPE}; then - log WARNING "${value} is already in the list of group-types of this policy." - else - list_append GROUP_TYPE ${value} - fi - fi + [A-Z0-9]*) + list_append group_types_set "${arg}" + ;; + *) + error "Invalid argument: ${arg}" + return ${EXIT_ERROR} ;; esac shift done - # Check if the list contain at least one valid group-type - if [ $(list_length ${GROUP_TYPE}) -ge 1 ]; then - if ! vpn_security_policies_write_config_key ${name} "GROUP_TYPE" ${GROUP_TYPE}; then - log ERROR "The changes for the vpn security policy ${name} could not be written." - fi + # Check if the user is trying a mixed operation + if ! list_is_empty group_types_set && (! list_is_empty group_types_added || ! list_is_empty group_types_removed); then + error "You cannot reset the group type list and add or remove group types at the same time" + return ${EXIT_ERROR} + fi + + # Set new group type list + if ! list_is_empty group_types_set; then + # Check if all group types are valid + local group_type + for group_type in ${group_types_set}; do + if ! vpn_security_policies_group_type_supported ${group_type}; then + error "Unsupported group type: ${group_type}" + return ${EXIT_ERROR} + fi + done + + GROUP_TYPES="${group_types_set}" + + # Perform incremental updates else - log ERROR "After proceding all group types the list is empty and thats why no changes are written." + local group_type + + # Perform all removals + for group_type in ${group_types_removed}; do + if ! list_remove GROUP_TYPES ${group_type}; then + warning "${group_type} was not on the list and could not be removed" + fi + done + + for group_type in ${group_types_added}; do + if vpn_security_policies_group_type_supported ${group_type}; then + if ! list_append_unique GROUP_TYPES ${group_type}; then + warning "${group_type} is already on the group type list" + fi + else + warning "${group_type} is unknown or unsupported and could not be added" + fi + done + fi + + # Check if the list contain at least one valid group_type + if list_is_empty GROUP_TYPES; then + error "Cannot save an empty group type list" return ${EXIT_ERROR} fi + + # Save everything + if ! vpn_security_policies_write_config_key ${name} "GROUP_TYPES" ${GROUP_TYPES}; then + log ERROR "The changes for the vpn security policy ${name} could not be written." + fi + + cli_headline 1 "Current group type list for ${name}:" + for group_type in ${GROUP_TYPES}; do + cli_print_fmt1 1 "${group_type}" "${VPN_SUPPORTED_GROUP_TYPES[${group_type}]}" + done } # This function parses the parameters for the 'integrity' command -vpn_security_policies_integrity(){ +vpn_security_policies_integrities() { local name=${1} shift if [ $# -eq 0 ]; then - log ERROR "You must pass at least one value after integrity." + log ERROR "You must pass at least one value" return ${EXIT_ERROR} fi - local INTEGRITY - if ! vpn_security_policies_read_config ${name} "INTEGRITY"; then + local INTEGRITIES + if ! vpn_security_policies_read_config ${name} "INTEGRITIES"; then return ${EXIT_ERROR} fi # Remove duplicated entries to proceed the list safely - INTEGRITY="$(list_unique ${INTEGRITY})" + INTEGRITIES="$(list_unique ${INTEGRITIES})" + + local integritys_added + local integritys_removed + local integritys_set while [ $# -gt 0 ]; do - case "${1}" in + local arg="${1}" + + case "${arg}" in + +*) + list_append integritys_added "${arg:1}" + ;; -*) - value=${1#-} - # Check if the integrity hash is in the list of integrity hashes and - # check if the list has after removing this integrity hash at least one valid value - if list_match ${value} ${INTEGRITY}; then - list_remove INTEGRITY ${value} - else - # We do not break here because the processing of other maybe valid values are indepent from this error. - log ERROR "Can not remove ${value} from the list of integrity hashes because ${value} is not in the list." - fi + list_append integritys_removed "${arg:1}" ;; - +*) - value=${1#+} - # Check if the Ciphers is in the list of supported integrity hashes. - 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 - if list_match ${value} ${INTEGRITY}; then - log WARNING "${value} is already in the list of integrety hashes of this policy." - else - list_append INTEGRITY ${value} - fi + [A-Z0-9]*) + list_append integritys_set "${arg}" + ;; + *) + error "Invalid argument: ${arg}" + return ${EXIT_ERROR} + ;; + esac + shift + done + + # Check if the user is trying a mixed operation + if ! list_is_empty integritys_set && (! list_is_empty integritys_added || ! list_is_empty integritys_removed); then + error "You cannot reset the integrity hashes list and add or remove integrity hashes at the same time" + return ${EXIT_ERROR} + fi + + # Set new integrity list + if ! list_is_empty integritys_set; then + # Check if all integrity hashes are valid + local integrity + for integrity in ${integritys_set}; do + if ! vpn_security_policies_integrity_supported ${integrity}; then + error "Unsupported integrity hash: ${integrity}" + return ${EXIT_ERROR} + fi + done + + INTEGRITIES="${integritys_set}" + + # Perform incremental updates + else + local integrity + + # Perform all removals + for integrity in ${integritys_removed}; do + if ! list_remove INTEGRITIES ${integrity}; then + warning "${integrity} was not on the list and could not be removed" + fi + done + + for integrity in ${integritys_added}; do + if vpn_security_policies_integrity_supported ${integrity}; then + if ! list_append_unique INTEGRITIES ${integrity}; then + warning "${integrity} is already on the integrity list" fi + else + warning "${integrity} is unknown or unsupported and could not be added" + fi + done + fi + + # Check if the list contain at least one valid integrity + if list_is_empty INTEGRITIES; then + error "Cannot save an empty integrity hashes list" + return ${EXIT_ERROR} + fi + + # Save everything + if ! vpn_security_policies_write_config_key ${name} "INTEGRITIES" ${INTEGRITIES}; then + log ERROR "The changes for the vpn security policy ${name} could not be written." + fi + + cli_headline 1 "Current integrity hashes list for ${name}:" + for integrity in ${INTEGRITIES}; do + cli_print_fmt1 1 "${integrity}" "${VPN_SUPPORTED_INTEGRITIES[${integrity}]}" + done +} + +# This function parses the parameters for the 'pseudo-random-functions' command +vpn_security_policies_pseudo_random_functions() { + local name=${1} + shift + + if [ $# -eq 0 ]; then + log ERROR "You must pass at least one value" + return ${EXIT_ERROR} + fi + + local PSEUDO_RANDOM_FUNCTIONS + if ! vpn_security_policies_read_config ${name} "PSEUDO_RANDOM_FUNCTIONS"; then + return ${EXIT_ERROR} + fi + + # Remove duplicated entries to proceed the list safely + PSEUDO_RANDOM_FUNCTIONS="$(list_unique ${PSEUDO_RANDOM_FUNCTIONS})" + + local prfs_added + local prfs_removed + local prfs_set + + while [ $# -gt 0 ]; do + local arg="${1}" + + case "${arg}" in + +*) + list_append prfs_added "${arg:1}" + ;; + -*) + list_append prfs_removed "${arg:1}" + ;; + [A-Z0-9]*) + list_append prfs_set "${arg}" + ;; + *) + error "Invalid argument: ${arg}" + return ${EXIT_ERROR} ;; esac shift done - # Check if the list contain at least one valid group-type - if [ $(list_length ${INTEGRITY}) -ge 1 ]; then - if ! vpn_security_policies_write_config_key ${name} "INTEGRITY" ${INTEGRITY}; then - log ERROR "The changes for the vpn security policy ${name} could not be written." - fi + # Check if the user is trying a mixed operation + if ! list_is_empty prfs_set && (! list_is_empty prfs_added || ! list_is_empty prfs_removed); then + error "You cannot reset the pseudo random function list and add or remove functions at the same time" + return ${EXIT_ERROR} + fi + + # Set new psudo random function list + if ! list_is_empty prfs_set; then + # Check if all PRFs are valid + local prf + for prf in ${prfs_set}; do + if ! vpn_security_policies_pseudo_random_function_supported "${prf}"; then + error "Unsupported pseudo random function: ${prf}" + return ${EXIT_ERROR} + fi + done + + PSEUDO_RANDOM_FUNCTIONS="${prfs_set}" + + # Perform incremental updates else - log ERROR "After proceding all integrity hashes the list is empty and thats why no changes are written." + local prf + + # Perform all removals + for prf in ${prfs_removed}; do + if ! list_remove PSEUDO_RANDOM_FUNCTIONS "${prf}"; then + warning "${prf} was not on the list and could not be removed" + fi + done + + for prf in ${prfs_added}; do + if vpn_security_policies_pseudo_random_function_supported "${prf}"; then + if ! list_append_unique PSEUDO_RANDOM_FUNCTIONS "${prf}"; then + warning "${prf} is already on the list" + fi + else + warning "${prf} is unknown or unsupported and could not be added" + fi + done + fi + + # Check if the list contain at least one valid value + if list_is_empty PSEUDO_RANDOM_FUNCTIONS; then + error "Cannot save an empty list of pseudo random functions" return ${EXIT_ERROR} fi + + # Save everything + if ! vpn_security_policies_write_config_key "${name}" "PSEUDO_RANDOM_FUNCTIONS" "${PSEUDO_RANDOM_FUNCTIONS}"; then + log ERROR "The changes for the VPN security policy ${name} could not be written" + fi + + cli_headline 1 "Current pseudo random function list for ${name}:" + for prf in ${PSEUDO_RANDOM_FUNCTIONS}; do + cli_print_fmt1 1 "${prf}" "${VPN_SUPPORTED_PSEUDO_RANDOM_FUNCTIONS[${prf}]}" + done } # This function parses the parameters for the 'key-exchange' command @@ -676,7 +1025,7 @@ vpn_security_policies_lifetime(){ fi if ! isinteger value; then - value=$(parse_time $@) + value=$(parse_time "$@") if [ ! $? -eq 0 ]; then log ERROR "Parsing the passed time was not sucessful please check the passed values." return ${EXIT_ERROR} @@ -760,7 +1109,7 @@ vpn_security_policies_new() { log DEBUG "Creating VPN Security Policy ${name}" - if copy "$(vpn_security_policies_path "${VPN_DEFAULT_SECURITY_POLICY}")" + 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 @@ -775,7 +1124,7 @@ vpn_security_policies_new() { # Function that deletes based on the passed parameters one ore more vpn security policies vpn_security_policies_destroy() { local name - for name in $@; do + for name in "$@"; do if ! vpn_security_policy_exists ${name}; then log ERROR "The vpn security policy ${name} does not exist." continue @@ -788,17 +1137,81 @@ vpn_security_policies_destroy() { log DEBUG "Deleting vpn security policy ${name}" settings_remove $(vpn_security_policies_path ${name}) + + # Delete cache + rm -rf "${NETWORK_CACHE_DIR}/vpn/security-policies/${name}" done } +vpn_security_policies_cipher_supported() { + local cipher=${1} + + list_match ${cipher} ${!VPN_SUPPORTED_CIPHERS[@]} +} + + +vpn_security_policies_group_type_supported() { + local group_type=${1} + + list_match ${group_type} ${!VPN_SUPPORTED_GROUP_TYPES[@]} +} + +vpn_security_policies_integrity_supported() { + local integrity=${1} + + list_match ${integrity} ${!VPN_SUPPORTED_INTEGRITIES[@]} +} + +vpn_security_policies_pseudo_random_function_supported() { + local prf="${1}" + + list_match "${prf}" ${!VPN_SUPPORTED_PSEUDO_RANDOM_FUNCTIONS[@]} +} + vpn_security_policies_cipher_is_aead() { local cipher=${1} # All CCM and GCM ciphers are AEAD - string_match "[CG]CM" "${cipher}" + if string_match "[CG]CM" "${cipher}"; then + return ${EXIT_TRUE} + fi + + # Poly1305 is AEAD + if string_match "POLY1305" "${cipher}"; then + return ${EXIT_TRUE} + fi + + return ${EXIT_FALSE} +} + +vpn_security_policies_make_ike_proposal() { + local name=${1} + + if ! vpn_security_policy_exists ${name}; then + return ${EXIT_ERROR} + fi + + local config_path="$(vpn_security_policies_path ${name})" + local cache_path="${NETWORK_CACHE_DIR}/vpn/security-policies/${name}/ike-proposal" + + # Get data from cache if possible + if file_exists "${cache_path}" && ! file_is_newer_than "${config_path}" "${cache_path}"; then + fread "${cache_path}" + return ${EXIT_OK} + fi + + # No or invalid cache data found + local proposal=$(_vpn_security_policies_make_ike_proposal "${name}") + + # Write proposal to cache + if ! make_parent_directory "${cache_path}" || ! fwrite "${cache_path}" "${proposal}"; then + log WARNING "Could not write to cache: ${cache_path}" + fi + + print "${proposal}" } -vpn_security_policies_make_ah_proposal() { +_vpn_security_policies_make_ike_proposal() { local name=${1} # Read the config settings @@ -810,7 +1223,7 @@ vpn_security_policies_make_ah_proposal() { local proposals local cipher - for cipher in ${CIPHER}; do + for cipher in ${CIPHERS}; do # Translate cipher local _cipher=${CIPHER_TO_STRONGSWAN[${cipher}]} @@ -819,28 +1232,53 @@ vpn_security_policies_make_ah_proposal() { continue fi - local integrity - for integrity in ${INTEGRITY}; do - local _integrity=${INTEGRITY_TO_STRONGSWAN[${integrity}]} + if vpn_security_policies_cipher_is_aead "${cipher}"; then + local prf + for prf in ${PSEUDO_RANDOM_FUNCTIONS}; do + local _prf="${PSEUDO_RANDOM_FUNCTION_TO_STRONGSWAN[${prf}]}" - if ! isset _integrity; then - log WARN "Unsupported integrity: ${integrity}" - continue - fi + if ! isset _prf; then + log WARN "Unsupported pseudo random function: ${prf}" + continue + fi - local group_type - for group_type in ${GROUP_TYPE}; do - local _group_type=${GROUP_TYPE_TO_STRONGSWAN[${group_type}]} + local group_type + for group_type in ${GROUP_TYPES}; do + local _group_type=${GROUP_TYPE_TO_STRONGSWAN[${group_type}]} - if ! isset _group_type; then - log WARN "Unsupported group-type: ${group_type}" + if ! isset _group_type; then + log WARN "Unsupported group-type: ${group_type}" + continue + fi + + # Put everything together + list_append proposals "${_cipher}-${_prf}-${_group_type}" + done + done + else + local integrity + for integrity in ${INTEGRITIES}; do + local _integrity=${INTEGRITY_TO_STRONGSWAN[${integrity}]} + + if ! isset _integrity; then + log WARN "Unsupported integrity: ${integrity}" continue fi - # Put everything together - list_append proposals "${_cipher}-${_integrity}-${_group_type}" + local group_type + for group_type in ${GROUP_TYPES}; 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 + fi done # Returns as a comma-separated list @@ -850,6 +1288,33 @@ vpn_security_policies_make_ah_proposal() { vpn_security_policies_make_esp_proposal() { local name=${1} + if ! vpn_security_policy_exists ${name}; then + return ${EXIT_ERROR} + fi + + local config_path="$(vpn_security_policies_path ${name})" + local cache_path="${NETWORK_CACHE_DIR}/vpn/security-policies/${name}/esp-proposal" + + # Get data from cache if possible + if file_exists "${cache_path}" && ! file_is_newer_than "${config_path}" "${cache_path}"; then + fread "${cache_path}" + return ${EXIT_OK} + fi + + # No or invalid cache data found + local proposal=$(_vpn_security_policies_make_esp_proposal "${name}") + + # Write proposal to cache + if ! make_parent_directory "${cache_path}" || ! fwrite "${cache_path}" "${proposal}"; then + log WARNING "Could not write to cache: ${cache_path}" + fi + + print "${proposal}" +} + +_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 @@ -859,7 +1324,7 @@ vpn_security_policies_make_esp_proposal() { local proposals local cipher - for cipher in ${CIPHER}; do + for cipher in ${CIPHERS}; do # Translate cipher local _cipher=${CIPHER_TO_STRONGSWAN[${cipher}]} @@ -870,7 +1335,7 @@ vpn_security_policies_make_esp_proposal() { if vpn_security_policies_cipher_is_aead ${cipher}; then local group_type - for group_type in ${GROUP_TYPE}; do + for group_type in ${GROUP_TYPES}; do local _group_type=${GROUP_TYPE_TO_STRONGSWAN[${group_type}]} if ! isset _group_type; then @@ -883,7 +1348,7 @@ vpn_security_policies_make_esp_proposal() { done else local integrity - for integrity in ${INTEGRITY}; do + for integrity in ${INTEGRITIES}; do local _integrity=${INTEGRITY_TO_STRONGSWAN[${integrity}]} if ! isset _integrity; then @@ -892,7 +1357,7 @@ vpn_security_policies_make_esp_proposal() { fi local group_type - for group_type in ${GROUP_TYPE}; do + for group_type in ${GROUP_TYPES}; do local _group_type=${GROUP_TYPE_TO_STRONGSWAN[${group_type}]} if ! isset _group_type; then @@ -910,3 +1375,15 @@ vpn_security_policies_make_esp_proposal() { # Returns as a comma-separated list list_join proposals , } + +# List all security policies +vpn_security_policies_list_all() { + list_directory "${NETWORK_SHARE_DIR}/vpn/security-policies" + + # Add all user-defined policies + vpn_security_policies_list_user +} + +vpn_security_policies_list_user() { + list_directory "${NETWORK_CONFIG_DIR}/vpn/security-policies" +}