Add support for Account Key Rollover (#7080)
Some checks failed
Apache / Apache (push) Has been cancelled
DNS / CheckToken (push) Has been cancelled
DragonFlyBSD / DragonFlyBSD (, , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
FreeBSD / FreeBSD (, , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
FreeBSD / FreeBSD (1, , , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
GhostBSD / GhostBSD (, , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
GhostBSD / GhostBSD (1, , , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
Haiku / Haiku (, , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
Haiku / Haiku (1, , , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
Linux / Linux (almalinux:latest) (push) Has been cancelled
Linux / Linux (alpine:latest) (push) Has been cancelled
Linux / Linux (archlinux:latest) (push) Has been cancelled
Linux / Linux (debian:latest) (push) Has been cancelled
Linux / Linux (fedora:latest) (push) Has been cancelled
Linux / Linux (gentoo/stage3) (push) Has been cancelled
Linux / Linux (kalilinux/kali) (push) Has been cancelled
Linux / Linux (opensuse/leap:latest) (push) Has been cancelled
Linux / Linux (oraclelinux:8) (push) Has been cancelled
Linux / Linux (ubuntu:latest) (push) Has been cancelled
MacOS / MacOS (, , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
MidnightBSD / MidnightBSD (, , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
NetBSD / NetBSD (, , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
Nginx / Nginx (push) Has been cancelled
Omnios / Omnios (, , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
Omnios / Omnios (1, , , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
OpenBSD / OpenBSD (, , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
OpenBSD / OpenBSD (1, , , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
OpenIndiana / OpenIndiana (, , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
OpenIndiana / OpenIndiana (1, , , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
PebbleStrict / PebbleStrict (push) Has been cancelled
PebbleStrict / PebbleStrict_IPCert (push) Has been cancelled
Solaris / Solaris (, , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
Solaris / Solaris (1, , , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
Tribblix / Tribblix (, , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
Tribblix / Tribblix (1, , , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
Ubuntu / Ubuntu (, , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
Ubuntu / Ubuntu (1, , , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
Ubuntu / Ubuntu (Smallstep Intermediate CA, Smallstep Intermediate CA, , 1, https://localhost:9000/acme/acme/directory, ) (push) Has been cancelled
Ubuntu / Ubuntu (Smallstep Intermediate CA, Smallstep Intermediate CA, , 1, https://localhost:9000/acme/acme/directory, 1, , 172.17.0.1) (push) Has been cancelled
Ubuntu / Ubuntu (ZeroSSL RSA DV SSL CA 2, ZeroSSL ECC DV SSL CA 2, githubtest@acme.sh, ZeroSSL.com, ) (push) Has been cancelled
Windows / Windows (, , , LetsEncrypt.org_test, (STAGING)) (push) Has been cancelled
Build DockerHub / CheckToken (push) Has been cancelled
Shellcheck / ShellCheck (push) Has been cancelled
Shellcheck / shfmt (push) Has been cancelled
DNS / Fail (push) Has been cancelled
DNS / Docker (push) Has been cancelled
DNS / MacOS (push) Has been cancelled
DNS / Windows (push) Has been cancelled
DNS / FreeBSD (push) Has been cancelled
DNS / GhostBSD (push) Has been cancelled
DNS / OpenBSD (push) Has been cancelled
DNS / NetBSD (push) Has been cancelled
DNS / DragonFlyBSD (push) Has been cancelled
DNS / MidnightBSD (push) Has been cancelled
DNS / Solaris (push) Has been cancelled
DNS / Omnios (push) Has been cancelled
DNS / OpenIndiana (push) Has been cancelled
DNS / Tribblix (push) Has been cancelled
DNS / Haiku (push) Has been cancelled
Build DockerHub / build (push) Has been cancelled

* add wiki

* feat: add support for account key rollover

* Place --update-account-key next to --update-account

* fix shfmt

* fix shfmt

* fix shfmt

* Fix from review

* fix shfmt

* fix from review

* fix review

---------

Co-authored-by: neil <gitpc@neilpang.com>
This commit is contained in:
Simon V. 2026-07-06 04:22:36 +02:00 committed by GitHub
parent 1f778e6ef1
commit ff9b969bdb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

94
acme.sh
View file

@ -4154,6 +4154,93 @@ updateaccount() {
fi
}
#Implement account key rollover
updateaccountkey() {
_length="$1"
_initpath
if [ ! -f "$ACCOUNT_KEY_PATH" ]; then
_err "Account key not found at: $ACCOUNT_KEY_PATH"
return 1
fi
ACCOUNT_KEY_PATH_NEW="$ACCOUNT_KEY_PATH.new"
_accUri=$(_readcaconf "ACCOUNT_URL")
_debug _accUri "$_accUri"
if [ -z "$_accUri" ]; then
_err "The account URL is empty, please run '--update-account' first to update the account info, then try again."
return 1
fi
if ! _calcjwk "$ACCOUNT_KEY_PATH"; then
return 1
fi
_inner_payload="{\"account\": \"$_accUri\", \"oldKey\": $jwk}"
_initAPI
if [ -z "$ACME_KEY_CHANGE" ]; then
_err "Server does not expose keyChange url."
return 1
fi
_url="$ACME_KEY_CHANGE"
if _createkey "$_length" "$ACCOUNT_KEY_PATH_NEW"; then
_info "New account key creation OK."
else
_err "New account key creation error."
return 1
fi
if ! _calcjwk "$ACCOUNT_KEY_PATH_NEW"; then
rm -f "$ACCOUNT_KEY_PATH_NEW"
return 1
fi
_inner_protected="{\"url\": \"${_url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}'
_inner_protected64="$(printf "%s" "$_inner_protected" | _base64 | _url_replace)"
_inner_payload64="$(printf "%s" "$_inner_payload" | _base64 | _url_replace)"
if ! _inner_sig_t="$(printf "%s" "$_inner_protected64.$_inner_payload64" | _sign "$ACCOUNT_KEY_PATH_NEW" "sha256")"; then
_err "Sign request failed."
rm -f "$ACCOUNT_KEY_PATH_NEW"
return 1
fi
_debug3 _inner_sig_t "$_inner_sig_t"
_inner_sig="$(printf "%s" "$_inner_sig_t" | _url_replace)"
_debug3 _inner_sig "$_inner_sig"
_body="{\"protected\": \"$_inner_protected64\", \"payload\": \"$_inner_payload64\", \"signature\": \"$_inner_sig\"}"
if ! _send_signed_request "$_url" "$_body" "" "$ACCOUNT_KEY_PATH"; then
_err "Error rotating account key: $response."
rm -f "$ACCOUNT_KEY_PATH_NEW"
return 1
fi
if [ "$code" = '200' ]; then
echo "$response" >"$ACCOUNT_JSON_PATH"
mv -f "$ACCOUNT_KEY_PATH_NEW" "$ACCOUNT_KEY_PATH"
_info "Account key rotation success for $_accUri."
elif [ "$code" = "409" ]; then
_err "An existing account is using the new key"
rm -f "$ACCOUNT_KEY_PATH_NEW"
return 1
else
_err "Account key rollover error: $response"
rm -f "$ACCOUNT_KEY_PATH_NEW"
return 1
fi
__CACHED_JWK_KEY_FILE=""
_calcjwk "$ACCOUNT_KEY_PATH"
ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)"
_info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT"
CA_KEY_HASH="$(__calcAccountKeyHash)"
_debug "Calc CA_KEY_HASH" "$CA_KEY_HASH"
_savecaconf CA_KEY_HASH "$CA_KEY_HASH"
}
#Implement deactivate account
deactivateaccount() {
_initpath
@ -7786,6 +7873,7 @@ Commands:
-ccr, --create-csr Create CSR, professional use.
--create-domain-key Create an domain private key, professional use.
--update-account Update account info.
--update-account-key Rotate account key.
--register-account Register account key.
--deactivate-account Deactivate the account.
--make-dns-persist-value Print the DNS TXT record(s) to enable persistent DNS validation
@ -8338,6 +8426,9 @@ _process() {
--update-account | --updateaccount)
_CMD="updateaccount"
;;
--update-account-key | --updateaccountkey)
_CMD="updateaccountkey"
;;
--register-account | --registeraccount)
_CMD="registeraccount"
;;
@ -8931,6 +9022,9 @@ _process() {
updateaccount)
updateaccount
;;
updateaccountkey)
updateaccountkey "$_accountkeylength"
;;
deactivateaccount)
deactivateaccount
;;