diff --git a/getssl b/getssl index 473f3e6..a688ca9 100755 --- a/getssl +++ b/getssl @@ -270,6 +270,7 @@ # 2021-07-30 Run tests with -d to catch intermittent failures, Use fork's repo for upgrade tests. (tlhackque) (#692) (2.41) # 2021-08-26 Improve upgrade check & make upgrade do a full install when possible (tlhackque) (#694) (2.42) # 2021-09-02 Fix version compare - cURL v8 may have single digit minor numbers. (tlhackque) (2.43) +# 2021-09-26 Delete key file when key algorithm has changed (makuhama) # ---------------------------------------------------------------------------------------- case :$SHELLOPTS: in @@ -838,7 +839,7 @@ check_getssl_upgrade() { # check if a more recent release is available fi if [[ ${_MUTE} -eq 0 ]]; then - echo "Updated getssl from v${VERSION} to v${release_tag}" + echo "Updated getssl from v${VERSION} to ${release_tag}" echo "The old version remains as ${0}.v${VERSION} and should be removed" echo "These update notifications can be turned off using the -Q option" echo "" @@ -3146,6 +3147,22 @@ else fi debug "created SAN list = $SANLIST" +# check if private key alg has changed from RSA to EC (or vice versa) +if [[ "$DUAL_RSA_ECDSA" == "false" ]] && [[ -s "$DOMAIN_DIR/${DOMAIN}.key" ]]; then + case "${PRIVATE_KEY_ALG}" in + rsa) + if grep --silent -- "-----BEGIN EC PRIVATE KEY-----" "$DOMAIN_DIR/${DOMAIN}.key"; then + rm -f "$DOMAIN_DIR/${DOMAIN}.key" + _FORCE_RENEW=1 + fi ;; + prime256v1|secp384r1|secp521r1) + if grep --silent -- "-----BEGIN RSA PRIVATE KEY-----" "$DOMAIN_DIR/${DOMAIN}.key"; then + rm -f "$DOMAIN_DIR/${DOMAIN}.key" + _FORCE_RENEW=1 + fi ;; + esac +fi + # if there is an existing certificate file, check details. if [[ -s "$CERT_FILE" ]]; then debug "certificate $CERT_FILE exists" @@ -3199,20 +3216,6 @@ if [[ "$REUSE_PRIVATE_KEY" != "true" ]]; then fi fi -# check if private key alg has changed from RSA to EC (or vice versa) -if [[ "$DUAL_RSA_ECDSA" == "false" ]] && [[ -s "$DOMAIN_DIR/${DOMAIN}.key" ]]; then - case "${PRIVATE_KEY_ALG}" in - rsa) - if grep --silent -- "-----BEGIN EC PRIVATE KEY-----" "$DOMAIN_DIR/${DOMAIN}.key"; then - rm -f "$DOMAIN_DIR/${DOMAIN}.key" - fi ;; - prime256v1|secp384r1|secp521r1) - if grep --silent -- "-----BEGIN RSA PRIVATE KEY-----" "$DOMAIN_DIR/${DOMAIN}.key"; then - rm -f "$DOMAIN_DIR/${DOMAIN}.key" - fi ;; - esac -fi - # create new domain keys if they don't already exist if [[ "$DUAL_RSA_ECDSA" == "false" ]]; then create_key "${PRIVATE_KEY_ALG}" "$DOMAIN_DIR/${DOMAIN}.key" "$DOMAIN_KEY_LENGTH" diff --git a/test/39-private-key-alg-changed.bats b/test/39-private-key-alg-changed.bats new file mode 100644 index 0000000..a8b0e43 --- /dev/null +++ b/test/39-private-key-alg-changed.bats @@ -0,0 +1,88 @@ +#! /usr/bin/env bats + +load '/bats-support/load.bash' +load '/bats-assert/load.bash' +load '/getssl/test/test_helper.bash' + + +# This is run for every test +teardown() { + [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_RUN_TMPDIR/failed.skip +} + +setup() { + [ ! -f $BATS_RUN_TMPDIR/failed.skip ] || skip "skipping tests after first failure" + export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt +} + +teardown_file() { + cleanup_environment +} + +@test "Create new certificate to create a private key" { + if [ -n "$STAGING" ]; then + skip "Using staging server, skipping internal test" + fi + CONFIG_FILE="getssl-http01.cfg" + setup_environment + init_getssl + create_certificate + assert_success + check_output_for_errors + # save a coy of the private key + cp "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.key" "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.key.orig" +} + +@test "Renew certificate (not force) and check nothing happens and key doesn't change" { + if [ -n "$STAGING" ]; then + skip "Using staging server, skipping internal test" + fi + + ORIG_KEY_HASH="$(cat ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.key | sha256sum)" + + run ${CODE_DIR}/getssl -U -d $GETSSL_HOST + assert_success + assert_line --partial "certificate is valid for more than 30 days" + check_output_for_errors + + NEW_KEY_HASH="$(cat ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.key | sha256sum)" + + assert [ "$NEW_KEY_HASH" == "$ORIG_KEY_HASH" ] +} + +@test "Force renewal and check key hasn't changed" { + if [ -n "$STAGING" ]; then + skip "Using staging server, skipping internal test" + fi + ORIG_KEY_HASH="$(cat ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.key | sha256sum)" + + run ${CODE_DIR}/getssl -U -d -f $GETSSL_HOST + assert_success + check_output_for_errors + + NEW_KEY_HASH="$(cat ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.key | sha256sum)" + + assert [ "$NEW_KEY_HASH" == "$ORIG_KEY_HASH" ] +} + +@test "Change key algorithm, force renewal, and check key has changed" { + if [ -n "$STAGING" ]; then + skip "Using staging server, skipping internal test" + fi + + ORIG_KEY_HASH="$(cat ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.key | sha256sum)" + + cat <<- 'EOF' > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg +PRIVATE_KEY_ALG="prime256v1" +EOF + + run ${CODE_DIR}/getssl -U -d $GETSSL_HOST + assert_success + refute_line --partial "certificate is valid for more than 30 days" + + check_output_for_errors + + NEW_KEY_HASH="$(cat ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.key | sha256sum)" + + assert [ "$NEW_KEY_HASH" != "$ORIG_KEY_HASH" ] +}