├── .gitattributes ├── test ├── README.md ├── all.sh ├── test_is_installed.sh ├── test_check_openssl_version.sh ├── test_check_server_version.sh ├── test_mount_filesystem.sh ├── test_add_fstab_entry.sh ├── test.sh ├── test_create_directory.sh ├── test_generate_key.sh ├── test_create_cron_job.sh ├── test_create_init_links.sh ├── test_create_init_dependency.sh ├── test_generate_keys.sh ├── test_change_owner_and_make_scripts_executable.sh ├── test_create_init_script.sh ├── test_check_filesystem.sh └── nginx_integration_test.sh ├── UNLICENSE ├── uninstall.sh ├── generator.sh ├── makefile ├── install.sh ├── README.md └── config.sh /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # Tests 2 | This directory contains very simple unit tests for most functions of the 3 | program. I thought about using [shUnit2](https://code.google.com/p/shunit2/) but 4 | because my time is limited I simply created a very simple framework for my tests 5 | on my own. I might convert them at a later point and make use of the above 6 | framework. 7 | 8 | ## Usage 9 | Each function is tested with its own script, this allows one to execute single 10 | tests. If you want to execute all tests simply use the `all.sh` script or issue 11 | `make test` (`sudo make test` respectively) in the parent directory. 12 | 13 | ## Integration Test 14 | The `integration_test.sh` is a special test that will install everything and 15 | create a TLS server on localhost with nginx. Afterwards it will check if the 16 | tickets are actually rotated. 17 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /test/all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # AUTHOR: Richard Fussenegger 32 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 33 | # LICENSE: http://unlicense.org/ PD 34 | # LINK: http://richard.fussenegger.info/ 35 | # ------------------------------------------------------------------------------ 36 | 37 | printf -- 'Testing ...\n ' 38 | for TEST in $(dirname "${0}")/test_*.sh 39 | do 40 | sh -- "${TEST}" 41 | done 42 | printf -- '\nFinished all tests!\n' 43 | -------------------------------------------------------------------------------- /test/test_is_installed.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # AUTHOR: Richard Fussenegger 32 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 33 | # LICENSE: http://unlicense.org/ PD 34 | # LINK: http://richard.fussenegger.info/ 35 | # ------------------------------------------------------------------------------ 36 | 37 | WD=$(cd -- $(dirname -- "${0}"); pwd) 38 | . "${WD}/test.sh" 39 | 40 | is_installed cp && test_ok || test_fail 41 | is_installed foo42bar && test_fail || test_ok 42 | -------------------------------------------------------------------------------- /test/test_check_openssl_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # AUTHOR: Richard Fussenegger 32 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 33 | # LICENSE: http://unlicense.org/ PD 34 | # LINK: http://richard.fussenegger.info/ 35 | # ------------------------------------------------------------------------------ 36 | 37 | WD=$(cd -- $(dirname -- "${0}"); pwd) 38 | . "${WD}/test.sh" 39 | 40 | check_openssl_version '0.0.1a' && test_ok || test_fail 41 | check_openssl_version "${OPENSSL_MIN_VERSION}" && test_ok || test_fail 42 | check_openssl_version '99.99.99z' && test_fail || test_ok 43 | 44 | # Equal 45 | V=$(openssl version) 46 | V="${V#* }" 47 | V="${V%% *}" 48 | check_openssl_version "${V}" && test_ok || test_fail 49 | -------------------------------------------------------------------------------- /test/test_check_server_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # AUTHOR: Richard Fussenegger 32 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 33 | # LICENSE: http://unlicense.org/ PD 34 | # LINK: http://richard.fussenegger.info/ 35 | # ------------------------------------------------------------------------------ 36 | 37 | WD=$(cd -- $(dirname -- "${0}"); pwd) 38 | . "${WD}/test.sh" 39 | 40 | check_server_version "${SERVER}" '0.0.1' && test_ok || test_fail 41 | check_server_version "${SERVER}" "${SERVER_MIN_VERSION}" && test_ok || test_fail 42 | check_server_version "${SERVER}" '99.99.99' && test_fail || test_ok 43 | 44 | # Equal 45 | V=$("${SERVER}" -v 2>&1 | head -n1) 46 | V="${V##*/}" 47 | check_server_version "${SERVER}" "${V}" && test_ok || test_fail 48 | -------------------------------------------------------------------------------- /test/test_mount_filesystem.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # AUTHOR: Richard Fussenegger 32 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 33 | # LICENSE: http://unlicense.org/ PD 34 | # LINK: http://richard.fussenegger.info/ 35 | # ------------------------------------------------------------------------------ 36 | 37 | WD=$(cd -- $(dirname -- "${0}"); pwd) 38 | . "${WD}/test.sh" 39 | 40 | TEST_DIR="${WD}/test" 41 | 42 | test_mount_filesystem_teardown() 43 | { 44 | umount -l -- "${TEST_DIR}" 45 | rmdir -- "${TEST_DIR}" 46 | } 47 | 48 | mkdir -p -- "${TEST_DIR}" 49 | 50 | trap -- test_mount_filesystem_teardown 0 1 2 3 6 9 14 15 51 | 52 | mount_filesystem 'ramfs' 'defaults' "${TEST_DIR}" && test_ok || test_fail 53 | grep -qs -- "${TEST_DIR}" /proc/mounts && test_ok || test_fail 54 | -------------------------------------------------------------------------------- /test/test_add_fstab_entry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # AUTHOR: Richard Fussenegger 32 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 33 | # LICENSE: http://unlicense.org/ PD 34 | # LINK: http://richard.fussenegger.info/ 35 | # ------------------------------------------------------------------------------ 36 | 37 | WD=$(cd -- $(dirname -- "${0}"); pwd) 38 | . "${WD}/test.sh" 39 | 40 | EXPECTED="${WD}/test_fstab_expected" 41 | ACTUAL="${WD}/test_fstab_actual" 42 | 43 | cat << EOT > "${EXPECTED}" 44 | # Volatile TLS session ticket key file system. 45 | ramfs /mnt/point ramfs defaults 0 0 46 | EOT 47 | 48 | touch -- "${ACTUAL}" 49 | 50 | trap -- "rm -f -- ${EXPECTED} ${ACTUAL}" 0 1 2 3 6 9 14 15 51 | 52 | add_fstab_entry 'ramfs' 'defaults' '/mnt/point' "${ACTUAL}" && test_ok || test_fail 53 | 54 | diff -- "${ACTUAL}" "${EXPECTED}" && test_ok || test_fail 55 | -------------------------------------------------------------------------------- /test/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # AUTHOR: Richard Fussenegger 32 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 33 | # LICENSE: http://unlicense.org/ PD 34 | # LINK: http://richard.fussenegger.info/ 35 | # ------------------------------------------------------------------------------ 36 | 37 | # Include the config file which contains all variables and functions. 38 | . "${WD}/../config.sh" 39 | super_user 40 | 41 | # Do not output anything. 42 | SILENT=true 43 | 44 | # Print green tick for successful test. 45 | # 46 | # RETURN: 47 | # 0 - Always 48 | test_ok() 49 | { 50 | printf -- '%s✔%s' "${GREEN}" "${NORMAL}" 51 | } 52 | 53 | # Print red x mark for unsuccessful test and exit with catchall error code. 54 | test_fail() 55 | { 56 | printf -- '\n[ %s✘%s ] %s failed!\n\n' "${RED}" "${NORMAL}" $(basename -- "${TEST_NAME:=${0}}" '.sh') 57 | exit 1 58 | } 59 | -------------------------------------------------------------------------------- /uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # TLS session ticket key uninstaller program. 32 | # 33 | # AUTHOR: Richard Fussenegger 34 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 35 | # LICENSE: http://unlicense.org/ PD 36 | # LINK: http://richard.fussenegger.info/ 37 | # ------------------------------------------------------------------------------ 38 | 39 | # Check return value of EVERY command / function and bail in case of non-zero. 40 | set -e 41 | 42 | # Complete the usage information for this program. 43 | DESCRIPTION='Uninstall TLS session ticket key rotation.' 44 | 45 | # Absolute path to the directory of this program. 46 | WD=$(cd -- $(dirname -- "${0}"); pwd) 47 | 48 | # Include the configuration with all variables and functions. 49 | . "${WD}/config.sh" 50 | 51 | # Make sure the program is executed by a super user (root / sudo). 52 | super_user 53 | 54 | # Uninstall TLS session ticket key rotation. 55 | uninstall 56 | 57 | exit 0 58 | -------------------------------------------------------------------------------- /test/test_create_directory.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # AUTHOR: Richard Fussenegger 32 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 33 | # LICENSE: http://unlicense.org/ PD 34 | # LINK: http://richard.fussenegger.info/ 35 | # ------------------------------------------------------------------------------ 36 | 37 | 38 | WD=$(cd -- $(dirname -- "${0}"); pwd) 39 | . "${WD}/test.sh" 40 | 41 | # Create paths to test directory and script. 42 | TEST_DIR="${WD}/test/test/test/test" 43 | 44 | # Clean-up on any signal including exit. 45 | trap -- "rmdir -p --ignore-fail-on-non-empty -- ${TEST_DIR}" 0 1 2 3 6 9 14 15 46 | 47 | create_directory "${TEST_DIR}" 'root' && test_ok || test_fail 48 | [ -d "${TEST_DIR}" ] && test_ok || test_fail 49 | [ $(stat --printf='%U' -- "${TEST_DIR}") = 'root' ] && test_ok || test_fail 50 | [ $(stat --printf='%G' -- "${TEST_DIR}") = 'root' ] && test_ok || test_fail 51 | [ $(stat --printf='%a' -- "${TEST_DIR}") -eq 550 ] && test_ok || test_fail 52 | -------------------------------------------------------------------------------- /test/test_generate_key.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # We can't validate random data, but we can check creation of file and length. 32 | # 33 | # AUTHOR: Richard Fussenegger 34 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 35 | # LICENSE: http://unlicense.org/ PD 36 | # LINK: http://richard.fussenegger.info/ 37 | # ------------------------------------------------------------------------------ 38 | 39 | WD=$(cd -- $(dirname -- "${0}"); pwd) 40 | . "${WD}/test.sh" 41 | 42 | TEST_FILE="${WD}/test_random_key" 43 | trap -- "rm -f ${TEST_FILE}" 0 1 2 3 6 9 14 15 44 | 45 | RANDOM_COMMAND='dd' 46 | generate_key "${TEST_FILE}" && test_ok || test_fail 47 | [ -f "${TEST_FILE}" ] && test_ok || test_fail 48 | [ $(stat --printf='%s' -- "${TEST_FILE}") -eq 48 ] && test_ok || test_fail 49 | rm -f "${TEST_FILE}" 50 | 51 | RANDOM_COMMAND='openssl' 52 | generate_key "${TEST_FILE}" && test_ok || test_fail 53 | [ -f "${TEST_FILE}" ] && test_ok || test_fail 54 | [ $(stat --printf='%s' -- "${TEST_FILE}") -eq 48 ] && test_ok || test_fail 55 | -------------------------------------------------------------------------------- /generator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # TLS session ticket key generator program. 32 | # 33 | # AUTHOR: Richard Fussenegger 34 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 35 | # LICENSE: http://unlicense.org/ PD 36 | # LINK: http://richard.fussenegger.info/ 37 | # ------------------------------------------------------------------------------ 38 | 39 | # Check return value of EVERY command / function and bail in case of non-zero. 40 | set -e 41 | 42 | # Complete the usage information for this program. 43 | ARGUMENTS='SERVER_NAME...' 44 | DESCRIPTION='Generate TLS session ticket keys for given server names.' 45 | 46 | # Absolute path to the directory of this program. 47 | WD=$(cd -- $(dirname -- "${0}"); pwd) 48 | 49 | # Include the configuration with all variables and functions. 50 | . "${WD}/config.sh" 51 | 52 | # Make sure the program was called correctly, we need the servers names. 53 | if [ "${#}" -lt 1 ] 54 | then 55 | usage 2>&1 56 | exit 1 57 | fi 58 | 59 | # Make sure the program is executed by a super user (root / sudo). 60 | super_user 61 | 62 | # Generate keys for all passed servers. 63 | generate_keys "${@}" 64 | 65 | exit 0 66 | -------------------------------------------------------------------------------- /test/test_create_cron_job.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # AUTHOR: Richard Fussenegger 32 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 33 | # LICENSE: http://unlicense.org/ PD 34 | # LINK: http://richard.fussenegger.info/ 35 | # ------------------------------------------------------------------------------ 36 | 37 | WD=$(cd -- $(dirname -- "${0}"); pwd) 38 | . "${WD}/test.sh" 39 | 40 | EXPECTED="${WD}/test_cron_expected" 41 | ACTUAL="${WD}/test_cron_actual" 42 | 43 | cat << EOT > "${EXPECTED}" 44 | # ------------------------------------------------------------------------------ 45 | # TLS session ticket key rotation. 46 | # 47 | # LINK: https://github.com/Fleshgrinder/nginx-session-ticket-key-rotation 48 | # ------------------------------------------------------------------------------ 49 | 50 | 0 0,12 * * * sh -- '${WD}' example.com localhost 51 | 30 0,12 * * * service nginx restart 52 | 53 | EOT 54 | 55 | touch -- "${ACTUAL}" 56 | 57 | trap -- "rm -f -- ${EXPECTED} ${ACTUAL}" 0 1 2 3 6 9 14 15 58 | 59 | create_cron_job "${ACTUAL}" "${WD}" 'example.com localhost' && test_ok || test_fail 60 | 61 | diff -- "${ACTUAL}" "${EXPECTED}" && test_ok || test_fail 62 | -------------------------------------------------------------------------------- /test/test_create_init_links.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # AUTHOR: Richard Fussenegger 32 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 33 | # LICENSE: http://unlicense.org/ PD 34 | # LINK: http://richard.fussenegger.info/ 35 | # ------------------------------------------------------------------------------ 36 | 37 | WD=$(cd -- $(dirname -- "${0}"); pwd) 38 | . "${WD}/test.sh" 39 | 40 | TEST_SCRIPT='/etc/init.d/nginx_session_ticket_key_rotation_test_script' 41 | TEST_FILE="${TEST_SCRIPT##*/}" 42 | 43 | cat << EOT > "${TEST_SCRIPT}" 44 | #!/bin/sh 45 | 46 | ### BEGIN INIT INFO 47 | # Provides: ${TEST_FILE} 48 | # Required-Start: 49 | # Required-Stop: 50 | # Default-Start: 2 3 4 5 51 | # Default-Stop: 52 | # Short-Description: 53 | # Description: 54 | ### END INIT INFO 55 | 56 | EOT 57 | 58 | test_create_init_links_teardown() 59 | { 60 | update-rc.d -f "${TEST_FILE}" remove >/dev/null 61 | rm -f ${TEST_SCRIPT} 62 | } 63 | 64 | trap -- test_create_init_links_teardown 0 1 2 3 6 9 14 15 65 | 66 | create_init_links "${TEST_SCRIPT}" && test_ok || test_fail 67 | 68 | for RUNLEVEL in 2 3 4 5 69 | do 70 | [ -L "/etc/rc${RUNLEVEL}.d/S10${TEST_FILE}" ] && test_ok || test_fail 71 | done 72 | -------------------------------------------------------------------------------- /test/test_create_init_dependency.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # AUTHOR: Richard Fussenegger 32 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 33 | # LICENSE: http://unlicense.org/ PD 34 | # LINK: http://richard.fussenegger.info/ 35 | # ------------------------------------------------------------------------------ 36 | 37 | WD=$(cd -- $(dirname -- "${0}"); pwd) 38 | . "${WD}/test.sh" 39 | 40 | EXPECTED="${WD}/test_init_expected" 41 | ACTUAL="${WD}/test_init_actual" 42 | 43 | cat << EOT > "${EXPECTED}" 44 | #!/bin/sh 45 | 46 | ### BEGIN INIT INFO 47 | # Provides: something 48 | # Required-Start: \$local_fs \$syslog \$dependency 49 | # Required-Stop: 50 | # Default-Start: 2 3 4 5 51 | # Default-Stop: 52 | # Short-Description: 53 | # Description: 54 | ### END INIT INFO 55 | 56 | EOT 57 | 58 | cat << EOT > "${ACTUAL}" 59 | #!/bin/sh 60 | 61 | ### BEGIN INIT INFO 62 | # Provides: something 63 | # Required-Start: \$local_fs \$syslog 64 | # Required-Stop: 65 | # Default-Start: 2 3 4 5 66 | # Default-Stop: 67 | # Short-Description: 68 | # Description: 69 | ### END INIT INFO 70 | 71 | EOT 72 | 73 | trap -- "rm -f -- ${EXPECTED} ${ACTUAL}" 0 1 2 3 6 9 14 15 74 | 75 | create_init_dependency /etc/init.d/dependency "${ACTUAL}" && test_ok || test_fail 76 | 77 | diff -- "${ACTUAL}" "${EXPECTED}" && test_ok || test_fail 78 | -------------------------------------------------------------------------------- /test/test_generate_keys.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # AUTHOR: Richard Fussenegger 32 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 33 | # LICENSE: http://unlicense.org/ PD 34 | # LINK: http://richard.fussenegger.info/ 35 | # ------------------------------------------------------------------------------ 36 | 37 | WD=$(cd -- $(dirname -- "${0}"); pwd) 38 | . "${WD}/test.sh" 39 | 40 | mkdir -p -- "${KEY_PATH}" 41 | trap -- "rm -rf ${KEY_PATH}" 0 1 2 3 6 9 14 15 42 | 43 | # Test key generation if no keys exist. 44 | generate_keys 'example.com' 'localhost' && test_ok || test_fail 45 | for SERVER_NAME in 'example.com' 'localhost' 46 | do 47 | for KEY in 1 2 3 48 | do 49 | [ -f "${KEY_PATH}/${SERVER_NAME}.${KEY}.key" ] && test_ok || test_fail 50 | done 51 | done 52 | 53 | # Backup old keys. 54 | for SERVER_NAME in 'example.com' 'localhost' 55 | do 56 | for KEY in 1 2 57 | do 58 | cp -- "${KEY_PATH}/${SERVER_NAME}.${KEY}.key" "${KEY_PATH}/${SERVER_NAME}.$(( ${KEY} + 1 )).bak" 59 | done 60 | done 61 | 62 | # Test key rotation if keys exist. 63 | generate_keys 'example.com' 'localhost' && test_ok || test_fail 64 | for SERVER_NAME in 'example.com' 'localhost' 65 | do 66 | for KEY in 2 3 67 | do 68 | diff -- "${KEY_PATH}/${SERVER_NAME}.${KEY}.key" "${KEY_PATH}/${SERVER_NAME}.${KEY}.bak" && test_ok || test_fail 69 | done 70 | done 71 | -------------------------------------------------------------------------------- /test/test_change_owner_and_make_scripts_executable.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # AUTHOR: Richard Fussenegger 32 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 33 | # LICENSE: http://unlicense.org/ PD 34 | # LINK: http://richard.fussenegger.info/ 35 | # ------------------------------------------------------------------------------ 36 | 37 | WD=$(cd -- $(dirname -- "${0}"); pwd) 38 | . "${WD}/test.sh" 39 | 40 | # Create paths to test directory and script. 41 | TEST_DIR="${WD}/test" 42 | TEST_FILE="${TEST_DIR}/file" 43 | TEST_SCRIPT="${TEST_DIR}/test.sh" 44 | 45 | # Create directory and script. 46 | mkdir -p -- "${TEST_DIR}" 47 | touch -- "${TEST_FILE}" 48 | touch -- "${TEST_SCRIPT}" 49 | 50 | # Clean-up on any signal including exit. 51 | trap -- "rm -rf ${TEST_DIR}" 0 1 2 3 6 9 14 15 52 | 53 | change_owner_and_make_scripts_executable "${TEST_DIR}" 'root' && test_ok || test_fail 54 | [ $(stat --printf='%U' -- "${TEST_DIR}") = 'root' ] && test_ok || test_fail 55 | [ $(stat --printf='%G' -- "${TEST_DIR}") = 'root' ] && test_ok || test_fail 56 | [ $(stat --printf='%a' -- "${TEST_DIR}") -eq 755 ] && test_ok || test_fail 57 | [ $(stat --printf='%U' -- "${TEST_FILE}") = 'root' ] && test_ok || test_fail 58 | [ $(stat --printf='%G' -- "${TEST_FILE}") = 'root' ] && test_ok || test_fail 59 | [ $(stat --printf='%a' -- "${TEST_FILE}") -eq 644 ] && test_ok || test_fail 60 | [ $(stat --printf='%U' -- "${TEST_SCRIPT}") = 'root' ] && test_ok || test_fail 61 | [ $(stat --printf='%G' -- "${TEST_SCRIPT}") = 'root' ] && test_ok || test_fail 62 | [ $(stat --printf='%a' -- "${TEST_SCRIPT}") -eq 744 ] && test_ok || test_fail 63 | -------------------------------------------------------------------------------- /test/test_create_init_script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # AUTHOR: Richard Fussenegger 32 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 33 | # LICENSE: http://unlicense.org/ PD 34 | # LINK: http://richard.fussenegger.info/ 35 | # ------------------------------------------------------------------------------ 36 | 37 | WD=$(cd -- $(dirname -- "${0}"); pwd) 38 | . "${WD}/test.sh" 39 | 40 | EXPECTED="${WD}/test_init_expected" 41 | ACTUAL="${WD}/test_init_actual" 42 | 43 | cat << EOT > "${EXPECTED}" 44 | #!/bin/sh 45 | 46 | ### BEGIN INIT INFO 47 | # Provides: test_init_actual 48 | # Required-Start: \$local_fs \$syslog 49 | # Required-Stop: 50 | # Default-Start: 2 3 4 5 51 | # Default-Stop: 52 | # Short-Description: Generates random TLS session ticket keys on boot. 53 | # Description: 54 | # The script will generate random TLS session ticket keys for all servers that 55 | # were defined during the installation of the program. The web server service 56 | # should specify this script as a dependency, this ensures that keys are 57 | # available on boot. 58 | ### END INIT INFO 59 | 60 | # ------------------------------------------------------------------------------ 61 | # TLS session ticket key rotation. 62 | # 63 | # LINK: https://github.com/Fleshgrinder/nginx-session-ticket-key-rotation 64 | # ------------------------------------------------------------------------------ 65 | 66 | sh '${WD}' example.com localhost 67 | 68 | EOT 69 | 70 | touch -- "${ACTUAL}" 71 | 72 | trap -- "rm -f -- ${EXPECTED} ${ACTUAL}" 0 1 2 3 6 9 14 15 73 | 74 | create_init_script "${ACTUAL}" "${WD}" 'example.com localhost' 75 | 76 | diff -- "${ACTUAL}" "${EXPECTED}" && test_ok || test_fail 77 | [ $(stat --printf='%U' -- "${ACTUAL}") = 'root' ] && test_ok || test_fail 78 | [ $(stat --printf='%G' -- "${ACTUAL}") = 'root' ] && test_ok || test_fail 79 | [ $(stat --printf='%a' -- "${ACTUAL}") -eq 755 ] && test_ok || test_fail 80 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------ 2 | # This is free and unencumbered software released into the public domain. 3 | # 4 | # Anyone is free to copy, modify, publish, use, compile, sell, or 5 | # distribute this software, either in source code form or as a compiled 6 | # binary, for any purpose, commercial or non-commercial, and by any 7 | # means. 8 | # 9 | # In jurisdictions that recognize copyright laws, the author or authors 10 | # of this software dedicate any and all copyright interest in the 11 | # software to the public domain. We make this dedication for the benefit 12 | # of the public at large and to the detriment of our heirs and 13 | # successors. We intend this dedication to be an overt act of 14 | # relinquishment in perpetuity of all present and future rights to this 15 | # software under copyright law. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | # OTHER DEALINGS IN THE SOFTWARE. 24 | # 25 | # For more information, please refer to 26 | # ------------------------------------------------------------------------------ 27 | 28 | # ------------------------------------------------------------------------------ 29 | # Makefile for easy pre-configured distribution of installation. 30 | # 31 | # AUTHOR: Richard Fussenegger 32 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 33 | # LICENSE: http://unlicense.org/ PD 34 | # LINK: http://richard.fussenegger.info/ 35 | # ------------------------------------------------------------------------------ 36 | 37 | 38 | # ------------------------------------------------------------------------------ 39 | # Variables 40 | # ------------------------------------------------------------------------------ 41 | 42 | 43 | # The server names to install or rotate for. 44 | SERVER_NAMES := example.com localhost 45 | 46 | # The name of the user the repository should own after clean. 47 | USER := fleshgrinder 48 | 49 | # The name of the group the repository should own after clean. 50 | GROUP := ${USER} 51 | 52 | 53 | # ------------------------------------------------------------------------------ 54 | # Targets 55 | # ------------------------------------------------------------------------------ 56 | 57 | 58 | # Ensure make doesn't think these targets are up-to-date because of an existing 59 | # directory. 60 | .PHONY: test 61 | 62 | # Mainly useful for testing. 63 | all: 64 | clear 65 | make test 66 | make nginx_integration_test 67 | -make install 68 | make clean 69 | 70 | # Clean everything and change repository owner back to default. 71 | clean: 72 | sh uninstall.sh -v 73 | chown -R -- ${USER}:${GROUP} . 74 | chmod -R -- 0755 . 75 | find . -type f -exec chmod -- 0644 {} \; 76 | find . -name '*.sh' -type f -exec chmod -- 0755 {} \; 77 | 78 | # Install TLS session ticket key rotation for defined servers. 79 | install: 80 | sh install.sh -v $(SERVER_NAMES) 81 | 82 | # Execute the integration test. 83 | nginx_integration_test: 84 | rm -f test/nginx.log 85 | sh test/nginx_integration_test.sh 86 | 87 | # Rotate existing TLS session ticket keys for defined servers. 88 | rotate: 89 | sh generator.sh -v $(SERVER_NAMES) 90 | 91 | # Execute all unit tests and final integration test. 92 | test: 93 | sh test/all.sh 94 | -------------------------------------------------------------------------------- /test/test_check_filesystem.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # AUTHOR: Richard Fussenegger 32 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 33 | # LICENSE: http://unlicense.org/ PD 34 | # LINK: http://richard.fussenegger.info/ 35 | # ------------------------------------------------------------------------------ 36 | 37 | WD=$(cd -- $(dirname -- "${0}"); pwd) 38 | . "${WD}/test.sh" 39 | 40 | # Create test filesystems file and delete on exit. 41 | TMP="${WD}/test_filesystems" 42 | trap -- "rm -f ${TMP}" 0 1 2 3 6 9 14 15 43 | 44 | # ------------------------------------------------------------------------------ 45 | # This fstab is taken from a Mint installation with ramfs. 46 | cat << EOT > "${TMP}" 47 | nodev sysfs 48 | nodev rootfs 49 | nodev ramfs 50 | nodev bdev 51 | nodev proc 52 | nodev cgroup 53 | nodev cpuset 54 | nodev tmpfs 55 | nodev devtmpfs 56 | nodev debugfs 57 | nodev securityfs 58 | nodev sockfs 59 | nodev pipefs 60 | nodev anon_inodefs 61 | nodev devpts 62 | ext3 63 | ext2 64 | ext4 65 | nodev hugetlbfs 66 | vfat 67 | nodev ecryptfs 68 | fuseblk 69 | nodev fuse 70 | nodev fusectl 71 | nodev pstore 72 | nodev mqueue 73 | nodev binfmt_misc 74 | nodev vboxsf 75 | xfs 76 | jfs 77 | msdos 78 | ntfs 79 | minix 80 | hfs 81 | hfsplus 82 | qnx4 83 | ufs 84 | btrfs 85 | EOT 86 | check_filesystem "${TMP}" && test_ok || test_fail 87 | [ "${FILESYSTEM}" = ramfs ] && test_ok || test_fail 88 | 89 | # ------------------------------------------------------------------------------ 90 | # This fstab is taken from an OVZ VPS. 91 | cat << EOT > "${TMP}" 92 | nodev cgroup 93 | nodev devpts 94 | nodev mqueue 95 | ext4 96 | nodev nfs 97 | nodev nfs4 98 | nodev delayfs 99 | nodev devtmpfs 100 | nodev sysfs 101 | nodev proc 102 | nodev tmpfs 103 | nodev binfmt_misc 104 | nodev fusectl 105 | nodev fuse 106 | EOT 107 | check_filesystem "${TMP}" && test_ok || test_fail 108 | [ "${FILESYSTEM}" = tmpfs ] && test_ok || test_fail 109 | 110 | # ------------------------------------------------------------------------------ 111 | # Well, you guessed. 112 | cat /dev/null > "${TMP}" 113 | check_filesystem "${TMP}" && test_fail || test_ok 114 | [ "${FILESYSTEM}" = false ] && test_ok || test_fail 115 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # TLS session ticket key install program. 32 | # 33 | # Note that user-defined function calls aren't documented in this script. Read 34 | # the functions documentation for more information, but usually the name of the 35 | # function should be sufficient to understand what's going on. 36 | # 37 | # AUTHOR: Richard Fussenegger 38 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 39 | # LICENSE: http://unlicense.org/ PD 40 | # LINK: http://richard.fussenegger.info/ 41 | # ------------------------------------------------------------------------------ 42 | 43 | # Check return value of EVERY command / function and bail in case of non-zero. 44 | set -e 45 | 46 | # Complete the usage information for this program. 47 | ARGUMENTS='SERVER_NAME...' 48 | DESCRIPTION='Install TLS session ticket key rotation for given server names.' 49 | 50 | # Absolute path to the directory of this program. 51 | WD=$(cd -- $(dirname -- "${0}"); pwd) 52 | 53 | # Include the configuration with all variables and functions. 54 | . "${WD}/config.sh" 55 | 56 | # Make sure that the program was called correctly, we need the servers names. 57 | if [ "${#}" -lt 1 ] 58 | then 59 | usage 2>&1 60 | exit 1 61 | fi 62 | 63 | [ "${VERBOSE}" = true ] && printf -- 'Checking environment ...\n' 64 | 65 | super_user 66 | check_ntpd 67 | is_installed "${SERVER}" 68 | check_server_version "${SERVER}" "${SERVER_MIN_VERSION}" 69 | check_filesystem "${FILESYSTEMS_PATH}" 70 | 71 | # Simple fail only checks, we have to make sure that the currently configured 72 | # paths, etc. won't destroy anything already present on this system. Note that 73 | # some checks are redundant but we want to be on the safe side. 74 | # 75 | # Read the fail message to understand what's going on. 76 | 77 | [ -d "${KEY_PATH}" ] && \ 78 | fail "Directory ${YELLOW}${KEY_PATH}${NORMAL} exists" 79 | 80 | grep -qs -- "${KEY_PATH}" /proc/mounts && \ 81 | fail "${YELLOW}${KEY_PATH}${NORMAL} already mounted" 82 | 83 | grep -qs -- "${FSTAB_COMMENT}" /etc/fstab && \ 84 | fail "${YELLOW}/etc/fstab${NORMAL} entry already exists" 85 | 86 | [ -f "${CRON_PATH}" ] && \ 87 | fail "Cron program ${YELLOW}${CRON_PATH}${NORMAL} already exists" 88 | 89 | [ -f "${INIT_PATH}" ] && \ 90 | fail "System startup program ${YELLOW}${INIT_PATH}${NORMAL} already exists" 91 | 92 | grep -qs -- " \$${INIT_NAME}" "${SERVER_INIT_PATH}" && \ 93 | fail "System startup dependency already exists in ${YELLOW}${SERVER_INIT_PATH}${NORMAL}" 94 | 95 | # Use a trap in case of any unforseen signals and rollback. 96 | trap uninstall 1 2 3 6 9 14 15 97 | 98 | [ "${VERBOSE}" = true ] && printf -- 'Installing ...\n' 99 | 100 | change_owner_and_make_scripts_executable "${WD}" 'root' 101 | create_directory "${KEY_PATH}" 'root' 102 | 103 | # Not all options have an effect if the preferred `ramfs` file system is used. 104 | readonly FILESYSTEM_OPTIONS="async,mode=770,noauto,noatime,nodev,nodiratime,"` 105 | `"noexec,nosuid,rw,size=${#}m" 106 | mount_filesystem "${FILESYSTEM}" "${FILESYSTEM_OPTIONS}" "${KEY_PATH}" 107 | add_fstab_entry "${FILESYSTEM}" "${FILESYSTEM_OPTIONS}" "${KEY_PATH}" '/etc/fstab' 108 | create_cron_job "${CRON_PATH}" "${WD}/generator.sh" "$(echo ${@})" 109 | generate_keys "${@}" 110 | create_init_script "${INIT_PATH}" "${WD}/generator.sh" "$(echo ${@})" 111 | create_init_links "${INIT_PATH}" 112 | create_init_dependency "${INIT_PATH}" "${SERVER_INIT_PATH}" 113 | 114 | [ "${VERBOSE}" = true ] && printf 'Installtion successful.\n' 115 | exit 0 116 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nginx session ticket key rotation 2 | [nginx](http://nginx.org/) session ticket key rotation program for secure 3 | rotation of TLS session ticket keys and sharing in server clusters. 4 | 5 | This program was developed as part of my Master's thesis at the 6 | [Fachhochschule Salzburg](https://github.com/fh-salzburg). I hope to release my 7 | thesis with an open license as soon as possible. You'll find much more details 8 | on TLS, its performance, and this program in there. Although I aim to provide a 9 | complete documentation for it here, I currently don't have the time to write it 10 | up because (you guessed) I'm working on the thesis. Feel free to open an issue 11 | if you have questions or found a bug. 12 | 13 | ## Usage 14 | You should clone the repository to a place were it can stay. The files are 15 | needed and shouldn't be deleted. The best place is `/etc` as illustrated in the 16 | following example. 17 | 18 | ``` 19 | cd /etc 20 | git clone https://github.com/Fleshgrinder/nginx-session-ticket-key-rotation.git 21 | sh nginx-session-ticket-key-rotation/install.sh example.com localhost 22 | ``` 23 | 24 | This would install TLS session ticket rotation for `example.com` and `localhost`. 25 | You have to edit your nginx configuration yourself afterwards, a minimal 26 | configuration with the default ticket lifetime of my installation for `localhost` 27 | would look like the following example. 28 | 29 | ``` 30 | http { 31 | server { 32 | listen 443 ssl; 33 | server_name localhost; 34 | ssl_certificate cert.pem; 35 | ssl_certificate_key cert.key; 36 | ssl_ciphers HIGH:!aNULL:!MD5; 37 | ssl_prefer_server_ciphers on; 38 | ssl_session_timeout 24h; 39 | ssl_session_ticket_key /mnt/session_ticket_keys/localhost.1.key; 40 | ssl_session_ticket_key /mnt/session_ticket_keys/localhost.2.key; 41 | ssl_session_ticket_key /mnt/session_ticket_keys/localhost.3.key; 42 | } 43 | } 44 | ``` 45 | 46 | To uninstall the rotation mechanism simply execute the `uninstall.sh` script. 47 | 48 | ``` 49 | sh nginx-session-ticket-key-rotation/uninstall.sh 50 | ``` 51 | 52 | ### Server Names 53 | You have to supply the server names (domains) to the installation script, this 54 | is important because you should only use a ticket key on a per host basis. 55 | You'll open your servers to various attacks (e.g. [5](#references)) if you share 56 | a keys among several hosts. The server names are also used to generate the key 57 | file names, which makes it easier for you to know which ticket belongs to which 58 | server. 59 | 60 | *Note* that there are situations where you want to share keys among several 61 | hosts. But I warned you, this is something that you should only attempt if you 62 | absolutely understand the potential risks and what it can be good for! 63 | 64 | ### Tests 65 | The repository includes unit tests for most functions and an integration test. 66 | To run the test either execute them separately (have a look at the test 67 | directory) or by issuing `make test`. 68 | 69 | You can safely delete the test directory if you don't want to waste disk space. 70 | 71 | ### Coding Standard 72 | The program should be as POSIX compliant as possible and everything was tested 73 | with the dash interpreter. Note that I prefer to use quotes around most strings 74 | because developers are used to do so in almost all other languages. Also note 75 | that there is a special dash bug related to closing `stdout` which is why I had 76 | to redirect `stdout` to `/dev/null` instead of directly closing it. The return 77 | values are always documented for each function, often that returned value is 78 | implicit returned by another called function. So you won't find a `return` 79 | statement in each function. 80 | 81 | The best place for information on POSIX is [The Open Group Base Specifications] 82 | (http://pubs.opengroup.org/onlinepubs/9699919799/nframe.html). 83 | 84 | ### TODO 85 | - Better error handling with a proper exit handler instead of `set -e` that 86 | gives a hint what actually went wrong. 87 | - Unit tests with [shUnit2](https://code.google.com/p/shunit2/). 88 | - Tell users to install something for better random numbers (esp. VPS), see 89 | [Havege](https://www.irisa.fr/caps/projects/hipsor/) 90 | ([`haveged`](https://packages.debian.org/wheezy/haveged)). 91 | - Tell users to test their random numbers 92 | ([`rngtest`](https://github.com/waitman/rngtest))? 93 | - Create slave program for clusters. 94 | - Install ntp daemon right away if none was found? 95 | - Test with other operating systems (currently only Debian tested). 96 | 97 | ## License 98 | > This is free and unencumbered software released into the public domain. 99 | > 100 | > For more information, please refer to 101 | 102 | ## References 103 | 1. Joseph Salowey, Harry Zhou, Pasi Eronen and Hannes Tschofenig: 104 | “[RFC 5077](https://tools.ietf.org/html/rfc5077)”, January, 2008. 105 | 2. Jacob Hoffman-Andrews: “[Forward Secrecy at Twitter] 106 | (https://blog.twitter.com/2013/forward-secrecy-at-twitter)”, November 22th, 2013. 107 | 3. Adam Langley: “[How to botch TLS forward secrecy] 108 | (https://www.imperialviolet.org/2013/06/27/botchingpfs.html)”, July 27th, 2013. 109 | 4. Jacob Hoffman-Andrews: “[How to check for TLS ticket key rotation] 110 | (https://jacob.hoffman-andrews.com/README/how-to-check-for-tls-ticket-key-rotation/)”, December 5th, 2013. 111 | 5. Antoine Delignat-Lavaud and Karthikeyan Bhargavan: 112 | “[Virtual Host Confusion: Weaknesses and Exploits] 113 | (https://www.blackhat.com/docs/us-14/materials/us-14-Delignat-The-BEAST-Wins-Again-Why-TLS-Keeps-Failing-To-Protect-HTTP-wp.pdf)”, August, 2014. 114 | 115 | ## Weblinks 116 | Other repositories of interest: 117 | - [nginx-configuration](https://github.com/Fleshgrinder/nginx-configuration) 118 | - [nginx-compile](https://github.com/Fleshgrinder/nginx-compile) 119 | - [nginx-sysvinit-script](https://github.com/Fleshgrinder/nginx-sysvinit-script) 120 | -------------------------------------------------------------------------------- /test/nginx_integration_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # Test if nginx is actually using the keys and if they are really rotated. 32 | # 33 | # AUTHOR: Richard Fussenegger 34 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 35 | # LICENSE: http://unlicense.org/ PD 36 | # LINK: http://richard.fussenegger.info/ 37 | # ------------------------------------------------------------------------------ 38 | 39 | 40 | set -e 41 | WD=$(cd -- $(dirname -- "${0}"); pwd) 42 | . "${WD}/test.sh" 43 | 44 | # ------------------------------------------------------------------------------ 45 | # Functions 46 | # ------------------------------------------------------------------------------ 47 | 48 | 49 | # Rotate session ticket keys and reload nginx. 50 | rotate() 51 | { 52 | TEST_NAME='rotate' 53 | sh "${WD}/../generator.sh" -s localhost || test_fail 54 | service nginx reload >/dev/null 2>&1 || test_fail 55 | unset TEST_NAME 56 | 57 | # We have to wait a second after rotating, otherwise nginx might not keep up. 58 | sleep 1 59 | } 60 | 61 | # Connect to localhost and get a new session ticket and store output. 62 | # 63 | # RETURN: 64 | # 0 - s_client successful. 65 | # 1 - s_client failed. 66 | s_client_new() 67 | { 68 | openssl s_client -connect localhost:443 "${WD}/conn" 2>&1 || test_fail 69 | } 70 | 71 | # Connect to localhost reusing existing ticket and storing output. 72 | # 73 | # RETURN: 74 | # 0 - s_client successful. 75 | # 1 - s_client failed. 76 | s_client_reuse() 77 | { 78 | openssl s_client -connect localhost:443 "${WD}/conn" 2>&1 || test_fail 79 | } 80 | 81 | # Clean-up everything on exit (any: see trap). 82 | teardown() 83 | { 84 | rm -f -- "${WD}/sess" 85 | rm -f -- "${WD}/conn" 86 | rm -f -- /etc/nginx/cert.key 87 | rm -f -- /etc/nginx/cert.pem 88 | 89 | # Restore the original nginx configuration. 90 | if [ -f /etc/nginx/nginx.bak ] 91 | then 92 | mv -- /etc/nginx/nginx.bak /etc/nginx/nginx.conf 93 | fi 94 | 95 | # Uninstall everything and reset the files to their original state. 96 | cd "${WD}/.." 97 | TEST_NAME='test_uninstall' 98 | make clean >/dev/null 2>&1 || test_fail 99 | TEST_NAME='test_git_reset' 100 | #git reset --hard >/dev/null 2>&1 || test_fail 101 | unset TEST_NAME 102 | } 103 | trap -- teardown 0 1 2 3 6 9 14 15 104 | 105 | # ------------------------------------------------------------------------------ 106 | # Setup 107 | # ------------------------------------------------------------------------------ 108 | 109 | 110 | check_openssl_version "${OPENSSL_MIN_VERSION}" 111 | 112 | # Generate private key and certificate for localhost server. 113 | TEST_NAME='test_key_cert' 114 | openssl req -x509 -nodes -days 1 -newkey rsa:2048 \ 115 | -keyout /etc/nginx/cert.key -out /etc/nginx/cert.pem << EOT >/dev/null 2>&1 || test_fail 116 | XX 117 | State 118 | City 119 | Company 120 | 121 | root 122 | root@localhost 123 | EOT 124 | unset TEST_NAME 125 | 126 | # Create new nginx configuration, be sure to create a backup of the original. 127 | if [ -f /etc/nginx/nginx.conf ] 128 | then 129 | cp -- /etc/nginx/nginx.conf /etc/nginx/nginx.bak 130 | fi 131 | 132 | # Create simple TLS server configuration for localhost. 133 | cat << EOT > /etc/nginx/nginx.conf 134 | worker_processes 1; 135 | error_log ${WD}/nginx.log debug; 136 | events { 137 | worker_connections 1024; 138 | } 139 | http { 140 | server { 141 | listen 443 ssl; 142 | server_name localhost; 143 | ssl_certificate cert.pem; 144 | ssl_certificate_key cert.key; 145 | ssl_ciphers HIGH:!aNULL:!MD5; 146 | ssl_prefer_server_ciphers on; 147 | ssl_session_timeout 36h; 148 | ssl_session_ticket_key ${KEY_PATH}/localhost.1.key; 149 | ssl_session_ticket_key ${KEY_PATH}/localhost.2.key; 150 | ssl_session_ticket_key ${KEY_PATH}/localhost.3.key; 151 | } 152 | } 153 | EOT 154 | 155 | # Install for localhost. 156 | cd "${WD}/.." 157 | make install >/dev/null 2>&1 158 | 159 | # Make sure everything is sane. 160 | nginx -t >/dev/null 2>&1 || test_fail 161 | 162 | # Restart or start nginx. 163 | if service nginx status >/dev/null 164 | then 165 | service nginx restart >/dev/null || test_fail 166 | else 167 | service nginx start >/dev/null || test_fail 168 | fi 169 | 170 | 171 | # ------------------------------------------------------------------------------ 172 | # Test 173 | # ------------------------------------------------------------------------------ 174 | 175 | 176 | printf ' ' 177 | 178 | # Connect and store session ticket and s_client output. 179 | s_client_new 180 | 181 | # Validate that we received a new session ticket. 182 | TEST_NAME='test_new_ticket' 183 | grep -Fq -- 'New, TLSv1/SSLv3, Cipher is' "${WD}/conn" || test_fail 184 | grep -Fq -- ' TLS session ticket lifetime hint: 129600 (seconds)' "${WD}/conn" || test_fail 185 | unset TEST_NAME 186 | 187 | test_ok 188 | 189 | # Extract the first hex line from the issued ticket. 190 | HEX_LINE=$(grep -F -- '0000 - ' "${WD}/conn") 191 | 192 | # Try to reconnect with the previous session ticket. 193 | s_client_reuse 194 | 195 | # Validate that we reused the previous ticket. 196 | TEST_NAME='test_reuse_ticket' 197 | grep -Fq -- 'Reused, TLSv1/SSLv3, Cipher is' "${WD}/conn" || test_fail 198 | grep -Fq -- "${HEX_LINE}" "${WD}/conn" || test_fail 199 | unset TEST_NAME 200 | 201 | test_ok 202 | 203 | # ------------------------------------------------------------------------------ 204 | # Rotate once. 205 | rotate 206 | 207 | # Try to reconnect with the previous session ticket. 208 | s_client_reuse 209 | 210 | # Validate that we reused the previous ticket but received new hex lines back. 211 | TEST_NAME='test_reuse_ticket_1' 212 | grep -Fq -- 'Reused, TLSv1/SSLv3, Cipher is' "${WD}/conn" || test_fail 213 | grep -Fq -- "${HEX_LINE}" "${WD}/conn" && test_fail 214 | unset TEST_NAME 215 | 216 | test_ok 217 | 218 | # Extract the first hex line from the newly issued ticket. 219 | s_client_new 220 | HEX_LINE=$(grep -F -- '0000 - ' "${WD}/conn") 221 | 222 | # ------------------------------------------------------------------------------ 223 | # Now let's rotate two times. 224 | rotate 225 | rotate 226 | 227 | # Try to reconnect with the previous session ticket. 228 | s_client_reuse 229 | 230 | # Validate that we reused the previous ticket but received new hex lines back. 231 | TEST_NAME='test_reuse_ticket_2' 232 | grep -Fq -- 'Reused, TLSv1/SSLv3, Cipher is' "${WD}/conn" || test_fail 233 | grep -Fq -- "${HEX_LINE}" "${WD}/conn" && test_fail 234 | unset TEST_NAME 235 | 236 | test_ok 237 | 238 | # ------------------------------------------------------------------------------ 239 | # Now let's rotate three times. 240 | rotate 241 | rotate 242 | rotate 243 | 244 | # Try to reconnect with the previous session ticket. 245 | s_client_reuse 246 | 247 | # We shouldn't be able to reuse our ticket. 248 | TEST_NAME='test_reuse_ticket_3' 249 | grep -Fq -- 'New, TLSv1/SSLv3, Cipher is' "${WD}/conn" || test_fail 250 | unset TEST_NAME 251 | 252 | test_ok 253 | 254 | 255 | # ------------------------------------------------------------------------------ 256 | # Teardown 257 | # ------------------------------------------------------------------------------ 258 | 259 | 260 | printf -- '%s✔%s - Integration test was successful, keys are rotating correctly!\n' "${GREEN}" "${NORMAL}" 261 | exit 0 262 | -------------------------------------------------------------------------------- /config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # This is free and unencumbered software released into the public domain. 5 | # 6 | # Anyone is free to copy, modify, publish, use, compile, sell, or 7 | # distribute this software, either in source code form or as a compiled 8 | # binary, for any purpose, commercial or non-commercial, and by any 9 | # means. 10 | # 11 | # In jurisdictions that recognize copyright laws, the author or authors 12 | # of this software dedicate any and all copyright interest in the 13 | # software to the public domain. We make this dedication for the benefit 14 | # of the public at large and to the detriment of our heirs and 15 | # successors. We intend this dedication to be an overt act of 16 | # relinquishment in perpetuity of all present and future rights to this 17 | # software under copyright law. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | # OTHER DEALINGS IN THE SOFTWARE. 26 | # 27 | # For more information, please refer to 28 | # ------------------------------------------------------------------------------ 29 | 30 | # ------------------------------------------------------------------------------ 31 | # Configuration file for TLS session ticket rotation program. 32 | # 33 | # AUTHOR: Richard Fussenegger 34 | # COPYRIGHT: Copyright (c) 2013 Richard Fussenegger 35 | # LICENSE: http://unlicense.org/ PD 36 | # LINK: http://richard.fussenegger.info/ 37 | # ------------------------------------------------------------------------------ 38 | 39 | 40 | # ------------------------------------------------------------------------------ 41 | # User Configurable Variables 42 | # ------------------------------------------------------------------------------ 43 | 44 | 45 | # The session ticket keys rotation interval as cron mask. 46 | # 47 | # Default is 12 hours which means that a key will reside in memory for 36 hours 48 | # before it's deleted (three keys are used). You shouldn't go for much more 49 | # than 24 hours for the encrypt key. 50 | # 51 | # The ticket's lifetime should be set to twice the lifetime of the encryption 52 | # key. 53 | readonly KEY_ROTATION='0 0,12 * * *' 54 | 55 | # The nginx rotation interval as cron mask. 56 | # 57 | # This should be after the keys have been rotated (see $KEY_ROTATION). Note 58 | # that keys are only in-use after nginx has read them. This is very important if 59 | # you're syncing the keys within a cluster. 60 | readonly SERVER_ROTATION='30 0,12 * * *' 61 | 62 | # Absolute path to the web server system startup program. 63 | readonly SERVER_INIT_PATH='/etc/init.d/nginx' 64 | 65 | # The minimum version the server has to have for session ticket keys via files. 66 | readonly SERVER_MIN_VERSION='1.5.7' 67 | 68 | # The minimum version the OpenSSL library requires for session ticket support. 69 | readonly OPENSSL_MIN_VERSION='0.9.8f' 70 | 71 | # Absolute path to the cron program. 72 | readonly CRON_PATH='/etc/cron.d/session_ticket_key_rotation' 73 | 74 | # Absolute path to the temporary file system. 75 | readonly KEY_PATH='/mnt/session_ticket_keys' 76 | 77 | # Absolute path to the system startup program. 78 | readonly INIT_PATH='/etc/init.d/session_ticket_keys' 79 | 80 | # Absolute path to the `filesystems` file. 81 | readonly FILESYSTEMS_PATH='/proc/filesystems' 82 | 83 | 84 | # ------------------------------------------------------------------------------ 85 | # Global System Variables 86 | # ------------------------------------------------------------------------------ 87 | 88 | 89 | # The comment that should be added to /etc/fstab for easy identification. 90 | readonly FSTAB_COMMENT='# Volatile TLS session ticket key file system.' 91 | 92 | # Name of the server daemon / executable. 93 | readonly SERVER="${SERVER_INIT_PATH##*/}" 94 | 95 | # For more information on shell colors and other text formatting see: 96 | # http://stackoverflow.com/a/4332530/1251219 97 | readonly RED=$(tput bold; tput setaf 1) 98 | readonly GREEN=$(tput bold; tput setaf 2) 99 | readonly YELLOW=$(tput bold; tput setaf 3) 100 | readonly UNDERLINE=$(tput smul) 101 | readonly NORMAL=$(tput sgr0) 102 | 103 | # This variable can be checked by scripts to see if they were included. 104 | readonly CONFIG_LOADED=true 105 | 106 | # Whether to suppress any output. 107 | SILENT=false 108 | 109 | # Whether we are verbose in outputting or not. 110 | VERBOSE=false 111 | 112 | 113 | # ------------------------------------------------------------------------------ 114 | # Global Functions 115 | # ------------------------------------------------------------------------------ 116 | 117 | 118 | # Add fstab entry. 119 | # 120 | # GLOBAL: 121 | # $FSTAB_COMMENT - The comment that's added in the line before the entry. 122 | # ARGS: 123 | # $1 - The desired file system to mount. 124 | # $2 - The file system's options 125 | # $3 - The path to the file system. 126 | # $4 - Absolute path to the fstab file. 127 | # RETURN: 128 | # 0 - Adding successful. 129 | # 1 - Adding failed. 130 | add_fstab_entry() 131 | { 132 | cat << EOT >> "${4}" || return 1 133 | ${FSTAB_COMMENT} 134 | ${1} ${3} ${1} ${2} 0 0 135 | EOT 136 | ok "Added ${YELLOW}${4}${NORMAL} entry" 137 | } 138 | 139 | # Change owner of a directory and all files in it and ensure shell scripts are 140 | # executable by the new owner only. 141 | # 142 | # ARGS: 143 | # $1 - Absolute path to the directory. 144 | # $2 - User and group name of the new owner. 145 | # RETURN: 146 | # 0 - If ownership was changed successfully. 147 | # 1 - If changing ownership failed. 148 | change_owner_and_make_scripts_executable() 149 | { 150 | chown -R -- "${2}":"${2}" "${1}" || return 1 151 | chmod -R -- 0755 "${1}" || return 1 152 | find "${1}" -type f -exec chmod -- 0644 {} \; || return 1 153 | find "${1}" -name '*.sh' -type f -exec chmod -- 0744 {} \; || return 1 154 | ok "Repository files owned and executable by ${2} users only" 155 | } 156 | 157 | # Check available file systems for availability of a volatile one. 158 | # 159 | # GLOBAL: 160 | # $FILESYSTEM - After calling this function this global variable is set to the 161 | # volatile file system that was found on this server. This is either `ramfs` 162 | # or `tmpfs`. The variable is set to `false` if no volatile file system could 163 | # be found. 164 | # ARGS: 165 | # $1 - Absolute path to the `filesystems` file. 166 | # RETURN: 167 | # 0 - Available 168 | # 1 - Not available 169 | check_filesystem() 170 | { 171 | if grep -q ramfs "${1}" 172 | then 173 | FILESYSTEM='ramfs' 174 | ok "Using ${YELLOW}ramfs${NORMAL}" 175 | elif grep -q tmpfs "${1}" 176 | then 177 | FILESYSTEM='tmpfs' 178 | warn "Using ${YELLOW}tmpfs${NORMAL} which means that your keys \ 179 | ${UNDERLINE}might${NORMAL} hit persistent storage if you have a swap" 180 | else 181 | FILESYSTEM=false 182 | fail "No support for ${YELLOW}ramfs${NORMAL} nor ${YELLOW}tmpfs${NORMAL} \ 183 | on this system" 184 | fi 185 | } 186 | 187 | # Check if an ntp daemon is installed. 188 | # 189 | # A correctly set system clock is imperative if keys are shared in cluster. 190 | # 191 | # NOTE: >&- nor 1>&- works in dash! 192 | # RETURN: 193 | # 0 - Always 194 | check_ntpd() 195 | { 196 | if type ntp >/dev/null 2>&1 197 | then 198 | ok "Found ${YELLOW}ntp${NORMAL}" 199 | elif type openntpd >/dev/null 2>&1 200 | then 201 | ok "Found ${YELLOW}openntpd${NORMAL}" 202 | elif type ntpdate >/dev/null 2>&1 203 | then 204 | warn "Found ${YELLOW}ntpdate${NORMAL} (deprecated)" 205 | else 206 | warn "Consider installing an ${YELLOW}ntp daemon${NORMAL} to set your \ 207 | system time and ensure all servers are in sync" 208 | fi 209 | } 210 | 211 | # Check OpenSSL version which has (of course) an awkward formatting. 212 | # 213 | # ARGS: 214 | # $1 - The minimum required version. 215 | # RETURN: 216 | # 0 - If version is equal or greater. 217 | # 1 - If version is lower. 218 | check_openssl_version() 219 | { 220 | # Example output: `OpenSSL 1.0.1f 6 Jan 2014` 221 | OPENSSL_VERSION=$(openssl version) 222 | 223 | OPENSSL_VERSION="${OPENSSL_VERSION#* }" # Remove smallest prefix space. 224 | OPENSSL_VERSION="${OPENSSL_VERSION%% *}" # Remove largest suffix space. 225 | # Now we have only `1.0.1f` left from above example. 226 | 227 | # This one's complicated. We need an integer for -ge comparison and therefore 228 | # remove the last character and all dots from the version string. Afterwards 229 | # we get the last character and convert it to its ASCII code point. 230 | # 231 | # Note the leading single quote in front of the second command, that's what 232 | # converts the character to its code point. 233 | V1=$(printf -- '%s%03d' \ 234 | "$(printf -- '%s' ${OPENSSL_VERSION} | head -c -1 | tr -d '.')" \ 235 | "'$(printf -- '%s' ${OPENSSL_VERSION} | tail -c -1)") 236 | 237 | # Now we need to do the same with the minimum version. 238 | V2=$(printf -- '%s%03d' \ 239 | "$(printf -- '%s' ${1} | head -c -1 | tr -d '.')" \ 240 | "'$(printf -- '%s' ${1} | tail -c -1)") 241 | 242 | # Greater or equals is what we are interested in. 243 | if [ "${V1}" -ge "${V2}" ] 244 | then 245 | ok "Installed OpenSSL version is ${YELLOW}${OPENSSL_VERSION}${NORMAL}" 246 | else 247 | fail "Installed OpenSSL version is ${YELLOW}${OPENSSL_VERSION}${NORMAL} \ 248 | which does not support session ticket keys. You need to install at least \ 249 | version ${YELLOW}${2}${NORMAL}" 250 | fi 251 | } 252 | 253 | # Check program version. 254 | # 255 | # NOTE: Works for nginx and Apache http (httpd). 256 | # ARGS: 257 | # $1 - The name of the program to check the version (must support -v option). 258 | # $2 - The minimum version. 259 | # RETURN: 260 | # 0 - If version is equal or greater. 261 | # 1 - If version is lower. 262 | check_server_version() 263 | { 264 | # Get version information from program. The head call isn't necessary for 265 | # nginx but it is for httpd because it will output something like: 266 | # Server version: Apache/2.4.10 267 | # Server built: Jul 09 2014 07:22:45 268 | SERVER_VERSION=$("${1}" -v 2>&1 | head -n1) 269 | 270 | # nginx: nginx version: nginx/1.7.6 (Ubuntu) 271 | # httpd: Server version: Apache/2.4.10 (Ubuntu) 272 | SERVER_VERSION="${SERVER_VERSION##*/}" # Remove longest match slash. 273 | # nginx: 1.7.6 (Ubuntu) 274 | # httpd: 2.4.10 (Ubuntu) 275 | 276 | # nginx: 1.7.6 (Ubuntu) 277 | # httpd: 2.4.10 (Ubuntu) 278 | SERVER_VERSION="${SERVER_VERSION%% *}" # Remove longest match space. 279 | # nginx: 1.7.6 280 | # httpd: 2.4.10 281 | 282 | # Remove dots. 283 | V1=$(printf -- '%s' "${SERVER_VERSION}" | tr -d '.') 284 | V2=$(printf -- '%s' "${2}" | tr -d '.') 285 | 286 | # Greater or equals is what we are interested in. 287 | if [ "${V1}" -ge "${V2}" ] 288 | then 289 | ok "Installed server version is ${YELLOW}${SERVER_VERSION}${NORMAL}" 290 | else 291 | fail "Installed server version is ${YELLOW}${SERVER_VERSION}${NORMAL} \ 292 | which does not support settings ticket keys via files. You need to install at \ 293 | least version ${YELLOW}${2}${NORMAL}" 294 | fi 295 | } 296 | 297 | # Create rotation cron job. 298 | # 299 | # GLOBALS: 300 | # $KEY_ROTATION - The key rotation cron mask. 301 | # $SERVER_ROTATION - The server rotation cron mask. 302 | # $SERVER - The name of the server daemon. 303 | # ARGS: 304 | # $1 - Absolute path to the cron file. 305 | # $2 - Absolute path to the rotation script. 306 | # $3 - The server names that should be passed to the rotation script. 307 | # RETURN: 308 | # 0 - Creation successful. 309 | # 1 - Creation failed. 310 | create_cron_job() 311 | { 312 | cat << EOT > "${1}" || return 1 313 | # ------------------------------------------------------------------------------ 314 | # TLS session ticket key rotation. 315 | # 316 | # LINK: https://github.com/Fleshgrinder/nginx-session-ticket-key-rotation 317 | # ------------------------------------------------------------------------------ 318 | 319 | ${KEY_ROTATION} sh -- '${2}' ${3} 320 | ${SERVER_ROTATION} service ${SERVER} reload 321 | 322 | EOT 323 | ok "Created cron rotation job ${YELLOW}${1}${NORMAL}" 324 | } 325 | 326 | # Create directory and ensure it's only accessible by given user and group. 327 | # 328 | # ARGS: 329 | # $1 - Absolute path to the directory that should be created. 330 | # $2 - User and group name of the owner. 331 | # RETURN: 332 | # 0 - If directory was successfully created. 333 | # 1 - If creation of directory failed. 334 | create_directory() 335 | { 336 | mkdir -p -- "${1}" || return 1 337 | chmod -- 0550 "${1}" || return 1 338 | chown -- "${2}":"${2}" "${1}" || return 1 339 | ok "Created directory ${YELLOW}${1}${NORMAL}" 340 | } 341 | 342 | # Create init dependency. 343 | # 344 | # ARGS: 345 | # $1 - Absolute path to the init script (the dependency). 346 | # $2 - Absolute path to the depending init script. 347 | # RETURN: 348 | # 0 - Creation successful. 349 | # 1 - Creation failed. 350 | create_init_dependency() 351 | { 352 | sed -i -- "/# Required-Start:/ s/\$/ \$${1##*/}/" "${2}" || return 1 353 | ok "Created system startup dependency in ${YELLOW}${2}${NORMAL}" 354 | } 355 | 356 | # Create init script links. 357 | # 358 | # NOTE: The runlevels are fixed to boot only and sequence to 10. 359 | # ARGS: 360 | # $1 - Absolute path to the init script to create links for. 361 | # RETURN: 362 | # 0 - Creation successful. 363 | # 1 - Creation failed. 364 | create_init_links() 365 | { 366 | update-rc.d "${1##*/}" start 10 2 3 4 5 . >/dev/null 2>&1 || return 1 367 | ok "Created system startup links for ${YELLOW}${1}${NORMAL}" 368 | } 369 | 370 | # Create init script. 371 | # 372 | # NOTE: The runlevels are fixed to boot only. 373 | # ARGS: 374 | # $1 - Absolute path to the init script. 375 | # $2 - Absolute path to the key generation script. 376 | # $3 - The server names that should be passed to the key generation script. 377 | # RETURN: 378 | # 0 - Creation successful. 379 | # 1 - Creation failed. 380 | create_init_script() 381 | { 382 | DAEMON_NAME="${1##*/}" 383 | cat << EOT > "${1}" || return 1 384 | #!/bin/sh 385 | 386 | ### BEGIN INIT INFO 387 | # Provides: ${DAEMON_NAME} 388 | # Required-Start: \$local_fs \$syslog 389 | # Required-Stop: 390 | # Default-Start: 2 3 4 5 391 | # Default-Stop: 392 | # Short-Description: Generates random TLS session ticket keys on boot. 393 | # Description: 394 | # The script will generate random TLS session ticket keys for all servers that 395 | # were defined during the installation of the program. The web server service 396 | # should specify this script as a dependency, this ensures that keys are 397 | # available on boot. 398 | ### END INIT INFO 399 | 400 | # ------------------------------------------------------------------------------ 401 | # TLS session ticket key rotation. 402 | # 403 | # LINK: https://github.com/Fleshgrinder/nginx-session-ticket-key-rotation 404 | # ------------------------------------------------------------------------------ 405 | 406 | sh '${2}' ${3} 407 | 408 | EOT 409 | chown -- root:root "${1}" || return 1 # Init scripts always belong to root. 410 | chmod -- 0755 "${1}" || return 1 # 0755 is the default for init scripts. 411 | ok "Created system startup program ${YELLOW}${1}${NORMAL} to generate keys on boot" 412 | } 413 | 414 | # Display fail message and exit program. 415 | # 416 | # ARGS: 417 | # $1 - The message's text. 418 | # RETURN: 419 | # 1 - Always 420 | fail() 421 | { 422 | if [ "${SILENT}" = false ] 423 | then 424 | printf "[%sfail%s] %s.\n" "${RED}" "${NORMAL}" "${1}" >&2 425 | fi 426 | return 1 427 | } 428 | 429 | # Generate (48 byte) random session ticket key. 430 | # 431 | # LINK: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/dd.html#tag_20_31 432 | # ARGS: 433 | # $1 - Absolute path to the key file. 434 | # RETURN: 435 | # 0 - If key generation was successful. 436 | # 1 - If key generation failed. 437 | generate_key() 438 | { 439 | dd 'if=/dev/random' "of=${1}" 'bs=1' 'count=48' 2>/dev/null || return 1 440 | } 441 | 442 | # Generate random keys for all servers. 443 | # 444 | # GLOBALS: 445 | # $KEY_PATH - Absolute path to the directory where the keys should be stored. 446 | # ARGS: 447 | # $@ - The server names to generate keys for. 448 | # RETURN: 449 | # 0 - Generation of all keys was successful. 450 | # 1 - Generation of keys failed. 451 | generate_keys() 452 | { 453 | [ "${VERBOSE}" = true ] && printf -- 'Generating random keys ...\n' 454 | 455 | for SERVER_NAME in ${@} 456 | do 457 | # Copy 2 over 3 and 1 over 2. 458 | for KEY in 2 1 459 | do 460 | OLD_KEY="${KEY_PATH}/${SERVER_NAME}.${KEY}.key" 461 | NEW_KEY="${KEY_PATH}/${SERVER_NAME}.$(( ${KEY} + 1 )).key" 462 | 463 | # Only perform copy operation if we actually have something to copy, 464 | # otherwise create file with random data to avoid web server errors. Note 465 | # that those files can't be used to decrypt anything, they are simple seed 466 | # data. 467 | if [ -f "${OLD_KEY}" ] 468 | then 469 | cp -- "${OLD_KEY}" "${NEW_KEY}" 470 | ok "Copied ${YELLOW}${OLD_KEY}${NORMAL} over ${YELLOW}${NEW_KEY}${NORMAL}" 471 | else 472 | generate_key "${NEW_KEY}" 473 | ok "Newly generated ${YELLOW}${NEW_KEY}${NORMAL}" 474 | fi 475 | done 476 | 477 | ENCRYPTION_KEY="${KEY_PATH}/${SERVER_NAME}.1.key" 478 | generate_key "${ENCRYPTION_KEY}" 479 | ok "Generated new encryption key ${YELLOW}${ENCRYPTION_KEY}${NORMAL}" 480 | done 481 | 482 | [ "${VERBOSE}" = true ] && printf -- 'Key generation finished!\n' 483 | return 0 484 | } 485 | 486 | # Check if given software is installed. 487 | # 488 | # ARGS: 489 | # $1 - The software to check. 490 | # RETURN: 491 | # 0 - Installed 492 | # 1 - Not installed 493 | is_installed() 494 | { 495 | if type "${1}" >/dev/null 2>&1 496 | then 497 | ok "${YELLOW}${1}${NORMAL} is installed" 498 | else 499 | fail "${YELLOW}${1}${NORMAL} does not seem to be installed" 500 | fi 501 | } 502 | 503 | # Mount file system. 504 | # 505 | # ARGS: 506 | # $1 - The desired file system to mount. 507 | # $2 - The file system's options 508 | # $3 - The path to the file system. 509 | # RETURN: 510 | # 0 - Mounting successful. 511 | # 1 - Mounting failed. 512 | mount_filesystem() 513 | { 514 | mount -t "${1}" -o "${2}" -- "${1}" "${3}" || return 1 515 | ok "Mounted ${YELLOW}${1}${NORMAL} on ${YELLOW}${3}${NORMAL}" 516 | } 517 | 518 | # Display ok message and continue program. 519 | # 520 | # Note that an ok message is only printed in verbose mode and if not silent. 521 | # 522 | # ARGS: 523 | # $1 - The message's text. 524 | # RETURN: 525 | # 0 - Message was printed to `stdout` 526 | # 1 - Printing of message failed. 527 | ok() 528 | { 529 | if [ "${VERBOSE}" = true ] && [ "${SILENT}" = false ] 530 | then 531 | printf -- "[ %sok%s ] %s ...\n" "${GREEN}" "${NORMAL}" "${1}" 532 | fi 533 | } 534 | 535 | # Check if super user is executing the program. 536 | # 537 | # RETURN: 538 | # 0 - Super user 539 | # 1 - No super user 540 | super_user() 541 | { 542 | UID=$(id -u) 543 | if [ "${UID}" -eq 0 ] 544 | then 545 | ok 'root (sudo)' 546 | else 547 | fail 'Program must be executed as root (sudo)' 548 | fi 549 | } 550 | 551 | # Uninstall TLS session ticket key rotation. 552 | # 553 | # TODO: Split into reusable, smaller, testable functions. 554 | # RETURN: 555 | # 0 - Uninstalled 556 | # 1 - Failure 557 | uninstall() 558 | { 559 | [ "${VERBOSE}" = true ] && printf -- 'Uninstalling ...\n' 560 | 561 | INIT_NAME="${INIT_PATH##*/}" 562 | if grep -q -- " \$${INIT_NAME}" "${SERVER_INIT_PATH}" 563 | then 564 | sed -i -- "s/ \$${INIT_NAME}//g" "${SERVER_INIT_PATH}" 565 | ok "Removed system startup dependency in ${YELLOW}${SERVER_INIT_PATH}${NORMAL}" 566 | else 567 | ok "System startup dependency already removed in ${YELLOW}${SERVER_INIT_PATH}${NORMAL}" 568 | fi 569 | 570 | update-rc.d -f "${INIT_NAME}" remove >/dev/null 2>&1 571 | ok "Removed any system startup links for ${YELLOW}${INIT_PATH}${NORMAL}" 572 | 573 | if [ -f "${INIT_PATH}" ] 574 | then 575 | rm -- "${INIT_PATH}" 576 | ok "Removed system startup program ${YELLOW}${INIT_PATH}${NORMAL}" 577 | else 578 | ok "System startup program ${YELLOW}${INIT_PATH}${NORMAL} already removed" 579 | fi 580 | 581 | if [ -f "${CRON_PATH}" ] 582 | then 583 | rm -- "${CRON_PATH}" 584 | ok "Removed cron program ${YELLOW}${CRON_PATH}${NORMAL}" 585 | else 586 | ok "Cron program ${YELLOW}${CRON_PATH}${NORMAL} already removed" 587 | fi 588 | 589 | if grep -q -- "${FSTAB_COMMENT}" /etc/fstab 590 | then 591 | sed -i -- "/${FSTAB_COMMENT}/,+1 d" '/etc/fstab' 592 | ok "Removed ${YELLOW}/etc/fstab${NORMAL} entry" 593 | else 594 | ok "No entry found in ${YELLOW}/etc/fstab${NORMAL}" 595 | fi 596 | 597 | if grep -q -- "${KEY_PATH}" /proc/mounts 598 | then 599 | umount -fl -- "${KEY_PATH}" 600 | ok "Unmounted ${YELLOW}${KEY_PATH}${NORMAL}" 601 | else 602 | ok "${YELLOW}${KEY_PATH}${NORMAL} already unmounted" 603 | fi 604 | 605 | if [ -d "${KEY_PATH}" ] 606 | then 607 | rmdir -- "${KEY_PATH}" 608 | ok "Removed directory ${YELLOW}${KEY_PATH}${NORMAL}" 609 | else 610 | ok "Directory ${YELLOW}${KEY_PATH}${NORMAL} does not exist" 611 | fi 612 | 613 | [ "${VERBOSE}" = true ] && printf -- 'Uninstallation finished!\n' 614 | return 0 615 | } 616 | 617 | # Print usage text. 618 | # 619 | # GLOBAL: 620 | # $ARGUMENTS - Program argument description. 621 | # $DESCRIPTION - Description what the program does. 622 | # RETURN: 623 | # 0 - Printing successful. 624 | # 1 - Printing failed. 625 | usage() 626 | { 627 | cat << EOT 628 | Usage: ${0##*/} [OPTION]... ${ARGUMENTS} 629 | ${DESCRIPTION} 630 | 631 | -h Display this help and exit. 632 | -s Be silent and do not print any message. 633 | -v Print message for each successful command. 634 | 635 | Report bugs to richard@fussenegger.info 636 | GitHub repository: https://github.com/Fleshgrinder/nginx-session-ticket-key-rotation 637 | For complete documentation, see: README.md 638 | EOT 639 | } 640 | 641 | # Display warn message and continue program. 642 | # 643 | # Note that a warn message is only printed if not silent. 644 | # 645 | # ARGS: 646 | # $1 - The message's text. 647 | # RETURN: 648 | # 0 - Message was printed to `stdout` 649 | # 1 - Printing of message failed. 650 | warn() 651 | { 652 | if [ "${SILENT}" = false ] 653 | then 654 | printf "[%swarn%s] %s ...\n" "${YELLOW}" "${NORMAL}" "${1}" 655 | fi 656 | } 657 | 658 | 659 | # ------------------------------------------------------------------------------ 660 | # Handle Options 661 | # ------------------------------------------------------------------------------ 662 | 663 | 664 | # Check for possibly passed options. 665 | while getopts 'hsv' OPT 666 | do 667 | case "${OPT}" in 668 | h) usage && exit 0 ;; 669 | s) SILENT=true ;; 670 | v) VERBOSE=true ;; 671 | *) usage 2>&1 && exit 1 ;; 672 | esac 673 | 674 | # We have to remove found options from the input for later evaluations of 675 | # passed arguments in subscripts that are not interested in these options. 676 | shift $(( $OPTIND - 1 )) 677 | done 678 | --------------------------------------------------------------------------------