From 034ec30c7d3f098007ffee704b00cf2d3c9b78e9 Mon Sep 17 00:00:00 2001 From: Lukas Schauer Date: Sat, 4 Jun 2016 03:58:07 +0200 Subject: [PATCH] added multi-account support (fixes #92, #163) --- .gitignore | 1 + CHANGELOG | 5 +++++ docs/examples/config | 3 +++ letsencrypt.sh | 33 +++++++++++++++++++++++++++------ test.sh | 9 +-------- 5 files changed, 37 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index d7bfa9b..26422e1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ config hook.sh certs/* archive/* +accounts/* .acme-challenges/* diff --git a/CHANGELOG b/CHANGELOG index 4bde971..e6cd343 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,10 +7,15 @@ This file contains a log of major changes in letsencrypt.sh - Location of domains.txt is now configurable via DOMAINS_TXT config variable - Location of certs directory is now configurable via CERTDIR config variable - signcsr command now also outputs chain certificate +- Location of account-key(s) changed ## Added - Added option to add CSR-flag indicating OCSP stapling to be mandatory - Initial support for configuration on per-certificate base +- Support for per-CA account keys and custom config for output cert directory, license, etc. + +## Fixed +- letsencrypt.sh no longer stores account keys from invalid registrations ## [0.2.0] - 2016-05-22 ### Changed diff --git a/docs/examples/config b/docs/examples/config index 23322e6..30a6e29 100644 --- a/docs/examples/config +++ b/docs/examples/config @@ -34,6 +34,9 @@ # Output directory for generated certificates #CERTDIR="${BASEDIR}/certs" +# Directory for account keys +#ACCOUNTDIR="${BASEDIR}/accounts" + # Output directory for challenge-tokens to be served by webserver or deployed in HOOK (default: $BASEDIR/.acme-challenges) #WELLKNOWN="${BASEDIR}/.acme-challenges" diff --git a/letsencrypt.sh b/letsencrypt.sh index 6c595ea..2d2522f 100755 --- a/letsencrypt.sh +++ b/letsencrypt.sh @@ -102,14 +102,13 @@ load_config() { CA="https://acme-v01.api.letsencrypt.org/directory" LICENSE="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf" CERTDIR= + ACCOUNTDIR= CHALLENGETYPE="http-01" CONFIG_D= DOMAINS_TXT= HOOK= HOOK_CHAIN="no" RENEW_DAYS="30" - ACCOUNT_KEY= - ACCOUNT_KEY_JSON= KEYSIZE="4096" WELLKNOWN= PRIVATE_KEY_RENEW="yes" @@ -157,8 +156,22 @@ load_config() { # Check BASEDIR and set default variables [[ -d "${BASEDIR}" ]] || _exiterr "BASEDIR does not exist: ${BASEDIR}" - [[ -z "${ACCOUNT_KEY}" ]] && ACCOUNT_KEY="${BASEDIR}/private_key.pem" - [[ -z "${ACCOUNT_KEY_JSON}" ]] && ACCOUNT_KEY_JSON="${BASEDIR}/private_key.json" + CAHASH="$(echo "${CA}" | urlbase64)" + [[ -z "${ACCOUNTDIR}" ]] && ACCOUNTDIR="${BASEDIR}/accounts" + mkdir -p "${ACCOUNTDIR}/${CAHASH}" + [[ -f "${ACCOUNTDIR}/${CAHASH}/config" ]] && . "${ACCOUNTDIR}/${CAHASH}/config" + ACCOUNT_KEY="${ACCOUNTDIR}/${CAHASH}/account_key.pem" + ACCOUNT_KEY_JSON="${ACCOUNTDIR}/${CAHASH}/registration_info.json" + + if [[ -f "${BASEDIR}/private_key.pem" ]] && [[ ! -f "${ACCOUNT_KEY}" ]]; then + echo "! Moving private_key.pem to ${ACCOUNT_KEY}" + mv "${BASEDIR}/private_key.pem" "${ACCOUNT_KEY}" + fi + if [[ -f "${BASEDIR}/private_key.json" ]] && [[ ! -f "${ACCOUNT_KEY_JSON}" ]]; then + echo "! Moving private_key.json to ${ACCOUNT_KEY_JSON}" + mv "${BASEDIR}/private_key.json" "${ACCOUNT_KEY_JSON}" + fi + [[ -z "${CERTDIR}" ]] && CERTDIR="${BASEDIR}/certs" [[ -z "${DOMAINS_TXT}" ]] && DOMAINS_TXT="${BASEDIR}/domains.txt" [[ -z "${WELLKNOWN}" ]] && WELLKNOWN="${BASEDIR}/.acme-challenges" @@ -225,10 +238,18 @@ init_system() { echo "+ Registering account key with letsencrypt..." [[ ! -z "${CA_NEW_REG}" ]] || _exiterr "Certificate authority doesn't allow registrations." # If an email for the contact has been provided then adding it to the registration request + FAILED=false if [[ -n "${CONTACT_EMAIL}" ]]; then - signed_request "${CA_NEW_REG}" '{"resource": "new-reg", "contact":["mailto:'"${CONTACT_EMAIL}"'"], "agreement": "'"$LICENSE"'"}' > "${ACCOUNT_KEY_JSON}" + (signed_request "${CA_NEW_REG}" '{"resource": "new-reg", "contact":["mailto:'"${CONTACT_EMAIL}"'"], "agreement": "'"$LICENSE"'"}' > "${ACCOUNT_KEY_JSON}") || FAILED=true else - signed_request "${CA_NEW_REG}" '{"resource": "new-reg", "agreement": "'"$LICENSE"'"}' > "${ACCOUNT_KEY_JSON}" + (signed_request "${CA_NEW_REG}" '{"resource": "new-reg", "agreement": "'"$LICENSE"'"}' > "${ACCOUNT_KEY_JSON}") || FAILED=true + fi + if [[ "${FAILED}" = "true" ]]; then + echo + echo + echo "Error registering account key. See message above for more information." + rm "${ACCOUNT_KEY}" "${ACCOUNT_KEY_JSON}" + exit 1 fi fi diff --git a/test.sh b/test.sh index 6c40405..0d81d69 100755 --- a/test.sh +++ b/test.sh @@ -114,7 +114,7 @@ _CHECK_ERRORLOG _TEST "First run in cron mode, checking if private key is generated and registered" ./letsencrypt.sh --cron > tmplog 2> errorlog || _FAIL "Script execution failed" _CHECK_LOG "Registering account key" -_CHECK_FILE "private_key.pem" +_CHECK_FILE accounts/*/account_key.pem _CHECK_ERRORLOG # Temporarily move config out of the way and try signing certificate by using temporary config location @@ -131,10 +131,6 @@ _CHECK_LOG "Done!" _CHECK_ERRORLOG mv tmp_config config -# Move private key and add new location to config -mv private_key.pem account_key.pem -echo 'PRIVATE_KEY="./account_key.pem"' >> config - # Add third domain to command-lime, should force renewal. _TEST "Run in cron mode again, this time adding third domain, should force renewal." ./letsencrypt.sh --cron --domain "${TMP_URL}" --domain "${TMP2_URL}" --domain "${TMP3_URL}" > tmplog 2> errorlog || _FAIL "Script execution failed" @@ -184,9 +180,6 @@ _CHECK_LOG "BEGIN CERTIFICATE" _CHECK_LOG "END CERTIFICATE" _CHECK_NOT_LOG "ERROR" -# Delete account key (not needed anymore) -rm account_key.pem - # Check if renewal works _TEST "Run in cron mode again, to check if renewal works" echo 'RENEW_DAYS="300"' >> config -- 2.47.3