]> git.ipfire.org Git - people/ms/network.git/blob - src/functions/functions.vpn-security-policies
security-policies: Import all ciphers that we support for now
[people/ms/network.git] / src / functions / functions.vpn-security-policies
1 #!/bin/bash
2 ###############################################################################
3 # #
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2017 IPFire Network Development Team #
6 # #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
11 # #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
16 # #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 # #
20 ###############################################################################
21
22 VPN_SECURITY_POLICIES_CONFIG_SETTINGS="CIPHER COMPRESSION GROUP_TYPE INTEGRITY KEY_EXCHANGE LIFETIME PFS"
23 VPN_SECURITY_POLICIES_READONLY="system"
24
25 VPN_DEFAULT_SECURITY_POLICY="system"
26
27 declare -A VPN_SUPPORTED_CIPHERS=(
28 # 3DES-CBC
29 [3DES-CBC]="168 bit 3DES-EDE-CBC"
30
31 # AES-CBC
32 [AES256-CBC]="256 bit AES-CBC"
33 [AES192-CBC]="192 bit AES-CBC"
34 [AES128-CBC]="128 bit AES-CBC"
35
36 # AES-CTR
37 [AES256-CTR]="256 bit AES-COUNTER"
38 [AES192-CTR]="192 bit AES-COUNTER"
39 [AES128-CTR]="128 bit AES-COUNTER"
40
41 # AES-GCM
42 [AES256-GCM128]="256 bit AES-GCM with 128 bit ICV"
43 [AES192-GCM128]="192 bit AES-GCM with 128 bit ICV"
44 [AES128-GCM128]="128 bit AES-GCM with 128 bit ICV"
45 [AES256-GCM96]="256 bit AES-GCM with 96 bit ICV"
46 [AES192-GCM96]="192 bit AES-GCM with 96 bit ICV"
47 [AES128-GCM96]="128 bit AES-GCM with 96 bit ICV"
48 [AES256-GCM64]="256 bit AES-GCM with 64 bit ICV"
49 [AES192-GCM64]="192 bit AES-GCM with 64 bit ICV"
50 [AES128-GCM64]="128 bit AES-GCM with 64 bit ICV"
51
52 # AES-CCM
53 [AES256-CCM128]="256 bit AES-CCM with 128 bit ICV"
54 [AES192-CCM128]="192 bit AES-CCM with 128 bit ICV"
55 [AES128-CCM128]="128 bit AES-CCM with 128 bit ICV"
56 [AES256-CCM96]="256 bit AES-CCM with 96 bit ICV"
57 [AES192-CCM96]="192 bit AES-CCM with 96 bit ICV"
58 [AES128-CCM96]="128 bit AES-CCM with 96 bit ICV"
59 [AES256-CCM64]="256 bit AES-CCM with 64 bit ICV"
60 [AES192-CCM64]="192 bit AES-CCM with 64 bit ICV"
61 [AES128-CCM64]="128 bit AES-CCM with 64 bit ICV"
62
63 # CAMELLIA-CBC
64 [CAMELLIA256-CBC]="256 bit CAMELLIA-CBC"
65 [CAMELLIA192-CBC]="192 bit CAMELLIA-CBC"
66 [CAMELLIA128-CBC]="128 bit CAMELLIA-CBC"
67
68 # CAMELLIA-CTR
69 [CAMELLIA256-CTR]="256 bit CAMELLIA-COUNTER"
70 [CAMELLIA192-CTR]="192 bit CAMELLIA-COUNTER"
71 [CAMELLIA128-CTR]="128 bit CAMELLIA-COUNTER"
72
73 # CAMELLIA-GCM
74 [CAMELLIA256-GCM128]="256 bit CAMELLIA-GCM with 128 bit ICV"
75 [CAMELLIA192-GCM128]="192 bit CAMELLIA-GCM with 128 bit ICV"
76 [CAMELLIA128-GCM128]="128 bit CAMELLIA-GCM with 128 bit ICV"
77 [CAMELLIA256-GCM96]="256 bit CAMELLIA-GCM with 96 bit ICV"
78 [CAMELLIA192-GCM96]="192 bit CAMELLIA-GCM with 96 bit ICV"
79 [CAMELLIA128-GCM96]="128 bit CAMELLIA-GCM with 96 bit ICV"
80 [CAMELLIA256-GCM64]="256 bit CAMELLIA-GCM with 64 bit ICV"
81 [CAMELLIA192-GCM64]="192 bit CAMELLIA-GCM with 64 bit ICV"
82 [CAMELLIA128-GCM64]="128 bit CAMELLIA-GCM with 64 bit ICV"
83
84 # CAMELLIA-CCM
85 [CAMELLIA256-CCM128]="256 bit CAMELLIA-CCM with 128 bit ICV"
86 [CAMELLIA192-CCM128]="192 bit CAMELLIA-CCM with 128 bit ICV"
87 [CAMELLIA128-CCM128]="128 bit CAMELLIA-CCM with 128 bit ICV"
88 [CAMELLIA256-CCM96]="256 bit CAMELLIA-CCM with 96 bit ICV"
89 [CAMELLIA192-CCM96]="192 bit CAMELLIA-CCM with 96 bit ICV"
90 [CAMELLIA128-CCM96]="128 bit CAMELLIA-CCM with 96 bit ICV"
91 [CAMELLIA256-CCM64]="256 bit CAMELLIA-CCM with 64 bit ICV"
92 [CAMELLIA192-CCM64]="192 bit CAMELLIA-CCM with 64 bit ICV"
93 [CAMELLIA128-CCM64]="128 bit CAMELLIA-CCM with 64 bit ICV"
94 )
95
96 VPN_SUPPORTED_INTEGRITY="SHA512 SHA256 SHA128"
97 VPN_SUPPORTED_GROUP_TYPES="MODP8192 MODP4096"
98
99 # This functions checks if a policy is readonly
100 # returns true when yes and false when no
101 vpn_security_policies_check_readonly() {
102 if isoneof name ${VPN_SECURITY_POLICIES_READONLY}; then
103 return ${EXIT_TRUE}
104 else
105 return ${EXIT_FALSE}
106 fi
107 }
108
109 # This function writes all values to a via ${name} specificated vpn security policy configuration file
110 vpn_security_policies_write_config() {
111 assert [ $# -ge 1 ]
112
113 local name="${1}"
114
115 if ! vpn_security_policy_exists "${name}"; then
116 log ERROR "No such vpn security policy: ${name}"
117 return ${EXIT_ERROR}
118 fi
119
120 if vpn_security_policies_check_readonly "${name}"; then
121 log ERROR "The ${name} vpn security policy cannot be changed."
122 return ${EXIT_ERROR}
123 fi
124
125 local path="$(vpn_security_policies_path "${name}")"
126 if [ ! -w ${path} ]; then
127 log ERROR "${path} is not writeable"
128 return ${EXIT_ERROR}
129 fi
130
131 if ! settings_write "${path}" ${VPN_SECURITY_POLICIES_CONFIG_SETTINGS}; then
132 log ERROR "Could not write configuration settings for vpn security policy ${name}"
133 return ${EXIT_ERROR}
134 fi
135
136 # TODO everytime we successfully write a config we should call some trigger to take the changes into effect
137 }
138
139 # This funtion writes the value for one key to a via ${name} specificated vpn security policy configuration file
140 vpn_security_policies_write_config_key() {
141 assert [ $# -ge 3 ]
142
143 local name=${1}
144 local key=${2}
145 shift 2
146
147 local value="$@"
148
149 if ! vpn_security_policy_exists "${name}"; then
150 log ERROR "No such vpn security policy: ${name}"
151 return ${EXIT_ERROR}
152 fi
153
154 log DEBUG "Set '${key}' to new value '${value}' in vpn security policy ${name}"
155
156 local ${VPN_SECURITY_POLICIES_CONFIG_SETTINGS}
157
158 # Read the config settings
159 if ! vpn_security_policies_read_config "${name}"; then
160 return ${EXIT_ERROR}
161 fi
162
163 # Set the key to a new value
164 assign "${key}" "${value}"
165
166 if ! vpn_security_policies_write_config "${name}"; then
167 return ${EXIT_ERROR}
168 fi
169
170 return ${EXIT_TRUE}
171 }
172
173 # Reads one or more keys out of a settings file or all if no key is provided.
174 vpn_security_policies_read_config() {
175 assert [ $# -ge 1 ]
176
177 local name="${1}"
178 shift 1
179
180 if ! vpn_security_policy_exists "${name}"; then
181 log ERROR "No such vpn security policy: ${name}"
182 return ${EXIT_ERROR}
183 fi
184
185
186 local args
187 if [ $# -eq 0 ] && [ -n "${VPN_SECURITY_POLICIES_CONFIG_SETTINGS}" ]; then
188 list_append args ${VPN_SECURITY_POLICIES_CONFIG_SETTINGS}
189 else
190 list_append args $@
191 fi
192
193 local path="$(vpn_security_policies_path ${name})"
194
195 if ! settings_read "${path}" ${args}; then
196 log ERROR "Could not read settings for vpn security policy ${name}"
197 return ${EXIT_ERROR}
198 fi
199 }
200
201 # Returns the path to a the configuration fora given name
202 vpn_security_policies_path() {
203 assert [ $# -eq 1 ]
204
205 local name=${1}
206
207 if vpn_security_policies_check_readonly "${name}"; then
208 echo "${NETWORK_SHARE_DIR}/vpn/security-policies/${name}"
209 else
210 echo "${NETWORK_CONFIG_DIR}/vpn/security-policies/${name}"
211 fi
212 }
213
214 # Print the content of a vpn security policy configuration file in a nice way
215 vpn_security_policies_show() {
216 assert [ $# -eq 1 ]
217
218 local name=${1}
219
220 local ${VPN_SECURITY_POLICIES_CONFIG_SETTINGS}
221 if ! vpn_security_policies_read_config ${name}; then
222 return ${EXIT_ERROR}
223 fi
224
225 cli_print_fmt1 0 "Security Policy: ${name}"
226 cli_space
227
228 # This could be done in a loop but a loop is much more complicated
229 # because we print 'Group Types' but the variable is named 'GROUP_TYPES'
230 cli_print_fmt1 1 "Ciphers:"
231 cli_print_fmt1 2 "${CIPHER}"
232 cli_space
233
234 cli_print_fmt1 1 "Integrity:"
235 cli_print_fmt1 2 "${INTEGRITY}"
236 cli_space
237
238 cli_print_fmt1 1 "Group Types:"
239 cli_print_fmt1 2 "${GROUP_TYPE}"
240 cli_space
241
242 cli_print_fmt1 1 "Key Exchange:" "${KEY_EXCHANGE}"
243
244 # Key Lifetime
245 if isinteger LIFETIME && [ ${LIFETIME} -gt 0 ]; then
246 cli_print_fmt1 1 "Key Lifetime:" "$(format_time ${LIFETIME})"
247 else
248 log ERROR "The value for Key Lifetime is not a valid integer greater zero."
249 fi
250
251 # PFS
252 if enabled PFS; then
253 cli_print_fmt1 1 "Perfect Forward Secrecy:" "enabled"
254 else
255 cli_print_fmt1 1 "Perfect Forward Secrecy:" "disabled"
256 fi
257 cli_space
258
259 # Compression
260 if enabled COMPRESSION; then
261 cli_print_fmt1 1 "Compression:" "enabled"
262 else
263 cli_print_fmt1 1 "Compression:" "disabled"
264 fi
265 cli_space
266 }
267
268 # This function checks if a vpn security policy exists
269 # Returns True when yes and false when not
270 vpn_security_policy_exists() {
271 assert [ $# -eq 1 ]
272
273 local name=${1}
274
275 local path=$(vpn_security_policies_path "${name}")
276
277 [ -f ${path} ] && return ${EXIT_TRUE} || return ${EXIT_FALSE}
278 }
279
280
281 # This function parses the parameters for the 'cipher' command
282 vpn_security_policies_cipher(){
283 local name=${1}
284 shift
285
286 if [ $# -eq 0 ]; then
287 log ERROR "You must pass at least one value after cipher"
288 return ${EXIT_ERROR}
289 fi
290
291 local CIPHER
292 if ! vpn_security_policies_read_config ${name} "CIPHER"; then
293 return ${EXIT_ERROR}
294 fi
295
296 # Remove duplicated entries to proceed the list safely
297 CIPHER="$(list_unique ${CIPHER})"
298
299 while [ $# -gt 0 ]; do
300 case "${1}" in
301 -*)
302 value=${1#-}
303 # Check if the cipher is in the list of ciphers and
304 # check if the list has after removing this cipher at least one valid value
305 if list_match ${value} ${CIPHER}; then
306 list_remove CIPHER ${value}
307 else
308 # We do not break here because this error does not break the processing of the next maybe valid values.
309 log ERROR "Can not remove ${value} from the list of Ciphers because ${value} is not in the list."
310 fi
311 ;;
312 +*)
313 value=${1#+}
314 # Check if the Ciphers is in the list of supported ciphers.
315 if ! isoneof value ${!VPN_SUPPORTED_CIPHERS[@]}; then
316 # We do not break here because this error does not break the processing of the next maybe valid values.
317 log ERROR "${value} is not a supported cipher and can thats why not added to the list of ciphers."
318 else
319 if list_match ${value} ${CIPHER}; then
320 log WARNING "${value} is already in the list of ciphers of this policy."
321 else
322 list_append CIPHER ${value}
323 fi
324 fi
325 ;;
326 esac
327 shift
328 done
329
330 # Check if the list contain at least one valid cipher
331 if [ $(list_length ${CIPHER}) -ge 1 ]; then
332 if ! vpn_security_policies_write_config_key ${name} "CIPHER" ${CIPHER}; then
333 log ERROR "The changes for the vpn security policy ${name} could not be written."
334 fi
335 else
336 log ERROR "After proceding all ciphers the list is empty and thats why no changes are written."
337 return ${EXIT_ERROR}
338 fi
339 }
340
341 # This function parses the parameters for the 'compression' command
342 vpn_security_policies_compression(){
343 local name=${1}
344 local value=${2}
345
346 # Check if we get only one argument after compression <name>
347 if [ ! $# -eq 2 ]; then
348 log ERROR "The number of arguments do not match. Only one argument after compression is allowed."
349 return ${EXIT_ERROR}
350 fi
351
352 if ! isbool value; then
353 # We suggest only two values to avoid overburding the user.
354 log ERROR "Invalid Argument ${value}"
355 return ${EXIT_ERROR}
356 fi
357
358 vpn_security_policies_write_config_key "${name}" "COMPRESSION" "${value}"
359 }
360
361 # This function parses the parameters for the 'group-type' command
362 vpn_security_policies_group_type(){
363 local name=${1}
364 shift
365
366 if [ $# -eq 0 ]; then
367 log ERROR "You must pass at least one value after group-type"
368 return ${EXIT_ERROR}
369 fi
370
371 local GROUP_TYPE
372 if ! vpn_security_policies_read_config ${name} "GROUP_TYPE"; then
373 return ${EXIT_ERROR}
374 fi
375
376 # Remove duplicated entries to proceed the list safely
377 GROUP_TYPE="$(list_unique ${GROUP_TYPE})"
378
379 while [ $# -gt 0 ]; do
380 case "${1}" in
381 -*)
382 value=${1#-}
383 # Check if the group type is in the list of group types and
384 # check if the list has after removing this group type at leatst one valid value
385 if list_match ${value} ${GROUP_TYPE}; then
386 list_remove GROUP_TYPE ${value}
387 else
388 # We do not break here because this error does not break the processing of the next maybe valid values.
389 log ERROR "Can not remove ${value} from the list of group types because ${value} is not in the list."
390 fi
391 ;;
392 +*)
393 value=${1#+}
394 # Check if the group type is in the list of supported group types.
395 if ! isoneof value ${VPN_SUPPORTED_GROUP_TYPES}; then
396 # We do not break here because the processing of other maybe valid values are indepent from this error.
397 log ERROR "${value} is not a supported group type and can thats why not added to the list of group types."
398 else
399 if list_match ${value} ${GROUP_TYPE}; then
400 log WARNING "${value} is already in the list of group-types of this policy."
401 else
402 list_append GROUP_TYPE ${value}
403 fi
404 fi
405 ;;
406 esac
407 shift
408 done
409
410 # Check if the list contain at least one valid group-type
411 if [ $(list_length ${GROUP_TYPE}) -ge 1 ]; then
412 if ! vpn_security_policies_write_config_key ${name} "GROUP_TYPE" ${GROUP_TYPE}; then
413 log ERROR "The changes for the vpn security policy ${name} could not be written."
414 fi
415 else
416 log ERROR "After proceding all group types the list is empty and thats why no changes are written."
417 return ${EXIT_ERROR}
418 fi
419 }
420
421 # This function parses the parameters for the 'integrity' command
422 vpn_security_policies_integrity(){
423 local name=${1}
424 shift
425
426 if [ $# -eq 0 ]; then
427 log ERROR "You must pass at least one value after integrity."
428 return ${EXIT_ERROR}
429 fi
430
431 local INTEGRITY
432 if ! vpn_security_policies_read_config ${name} "INTEGRITY"; then
433 return ${EXIT_ERROR}
434 fi
435
436 # Remove duplicated entries to proceed the list safely
437 INTEGRITY="$(list_unique ${INTEGRITY})"
438
439 while [ $# -gt 0 ]; do
440 case "${1}" in
441 -*)
442 value=${1#-}
443 # Check if the integrity hash is in the list of integrity hashes and
444 # check if the list has after removing this integrity hash at least one valid value
445 if list_match ${value} ${INTEGRITY}; then
446 list_remove INTEGRITY ${value}
447 else
448 # We do not break here because the processing of other maybe valid values are indepent from this error.
449 log ERROR "Can not remove ${value} from the list of integrity hashes because ${value} is not in the list."
450 fi
451 ;;
452 +*)
453 value=${1#+}
454 # Check if the Ciphers is in the list of supported integrity hashes.
455 if ! isoneof value ${VPN_SUPPORTED_INTEGRITY}; then
456 # We do not break here because the processing of other maybe valid values are indepent from this error.
457 log ERROR "${value} is not a supported integrity hash and can thats why not added to the list of integrity hashes."
458 else
459 if list_match ${value} ${INTEGRITY}; then
460 log WARNING "${value} is already in the list of integrety hashes of this policy."
461 else
462 list_append INTEGRITY ${value}
463 fi
464 fi
465 ;;
466 esac
467 shift
468 done
469
470 # Check if the list contain at least one valid group-type
471 if [ $(list_length ${INTEGRITY}) -ge 1 ]; then
472 if ! vpn_security_policies_write_config_key ${name} "INTEGRITY" ${INTEGRITY}; then
473 log ERROR "The changes for the vpn security policy ${name} could not be written."
474 fi
475 else
476 log ERROR "After proceding all integrity hashes the list is empty and thats why no changes are written."
477 return ${EXIT_ERROR}
478 fi
479 }
480
481 # This function parses the parameters for the 'key-exchange' command
482 vpn_security_policies_key_exchange() {
483 local name=${1}
484 local value=${2}
485
486 # Check if we get only one argument after key-exchange <name>
487 if [ ! $# -eq 2 ]; then
488 log ERROR "The number of arguments do not match. Only argument after key-exchange is allowed."
489 return ${EXIT_ERROR}
490 fi
491
492 if ! isoneof value "ikev1" "ikev2" "IKEV1" "IKEV2"; then
493 log ERROR "Invalid Argument ${value}"
494 return ${EXIT_ERROR}
495 fi
496
497 vpn_security_policies_write_config_key "${name}" "KEY_EXCHANGE" "${value,,}"
498 }
499
500 # This function parses the parameters for the 'lifetime' command.
501 vpn_security_policies_lifetime(){
502 local name=${1}
503 shift
504
505 local value=$@
506
507 # Check if we get only one argument after lifetime <name>
508 if [ ! $# -ge 1 ]; then
509 log ERROR "The number of arguments do not match you must provide at least one integer value or a valid time with the format <hours>h <minutes>m <seconds>s"
510 return ${EXIT_ERROR}
511 fi
512
513 if ! isinteger value; then
514 value=$(parse_time $@)
515 if [ ! $? -eq 0 ]; then
516 log ERROR "Parsing the passed time was not sucessful please check the passed values."
517 return ${EXIT_ERROR}
518 fi
519 fi
520
521 if [ ${value} -le 0 ]; then
522 log ERROR "The passed time value must be in the sum greater zero seconds."
523 return ${EXIT_ERROR}
524 fi
525
526 vpn_security_policies_write_config_key "${name}" "LIFETIME" "${value}"
527 }
528
529 # This function parses the parameters for the 'pfs' command
530 vpn_security_policies_pfs(){
531 local name=${1}
532 local value=${2}
533
534 # Check if we get only one argument after pfs <name>
535 if [ ! $# -eq 2 ]; then
536 log ERROR "The number of arguments do not match. Only argument after pfs is allowed."
537 return ${EXIT_ERROR}
538 fi
539
540 if [ ! $# -eq 2 ] || ! isbool value; then
541 # We suggest only two values to avoid overburding the user.
542 log ERROR "Invalid Argument ${value}"
543 return ${EXIT_ERROR}
544 fi
545
546 vpn_security_policies_write_config_key "${name}" "PFS" "${value}"
547 }
548
549 # This function checks if a vpn security policy name is valid
550 # Allowed are only A-Za-z0-9
551 vpn_security_policies_check_name() {
552 assert [ $# -eq 1 ]
553
554 local name=${1}
555
556 [[ ${name} =~ [^[:alnum:]$] ]]
557 }
558
559 # Function that creates based on the paramters one ore more new vpn security policies
560 vpn_security_policies_new() {
561 if [ $# -gt 1 ]; then
562 error "Too many arguments"
563 return ${EXIT_ERROR}
564 fi
565
566 local name="${1}"
567 if ! isset name; then
568 error "Please provide a name"
569 return ${EXIT_ERROR}
570 fi
571
572 # Check for duplicates
573 if vpn_security_policy_exists "${name}"; then
574 error "The VPN security policy with name ${name} already exists"
575 return ${EXIT_ERROR}
576 fi
577
578 # Check if name is valid
579 if vpn_security_policies_check_name "${name}"; then
580 error "'${name}' contains illegal characters"
581 return ${EXIT_ERROR}
582 fi
583
584 # Check if we have a read-only policy with the same name
585 if vpn_security_policies_check_readonly "${name}"; then
586 error "The VPN security policy ${name} is read-only"
587 return ${EXIT_ERROR}
588 fi
589
590 # Check if our source policy exists
591 if ! vpn_security_policy_exists "${VPN_DEFAULT_SECURITY_POLICY}"; then
592 error "Default VPN Security Policy '${VPN_DEFAULT_SECURITY_POLICY}' does not exist"
593 return ${EXIT_ERROR}
594 fi
595
596 log DEBUG "Creating VPN Security Policy ${name}"
597
598 if copy "$(vpn_security_policies_path "${VPN_DEFAULT_SECURITY_POLICY}")"
599 "$(vpn_security_policies_path ${name})"; then
600 log INFO "VPN Security Policy ${name} successfully created"
601 else
602 log ERROR "Could not create VPN Security Policy ${name}"
603 return ${EXIT_ERROR}
604 fi
605
606 # Show the newly created policy
607 vpn_security_policies_show "${name}"
608 }
609
610 # Function that deletes based on the passed parameters one ore more vpn security policies
611 vpn_security_policies_destroy() {
612 local name
613 for name in $@; do
614 if ! vpn_security_policy_exists ${name}; then
615 log ERROR "The vpn security policy ${name} does not exist."
616 continue
617 fi
618
619 if vpn_security_policies_check_readonly ${name}; then
620 log ERROR "The vpn security policy ${name} cannot be deleted."
621 continue
622 fi
623
624 log DEBUG "Deleting vpn security policy ${name}"
625 settings_remove $(vpn_security_policies_path ${name})
626 done
627 }