diff --git a/README.md b/README.md index 90280e94..2d0e130c 100644 --- a/README.md +++ b/README.md @@ -227,6 +227,31 @@ Cron entry example: acme.sh -h ``` +#### 🔏 Verify a Release + +Release tags from `3.1.5` on are signed with the maintainer's SSH key. The +signing happens on the maintainer's machine, so the private key is never +available to CI. The public half is [`allowed_signers`](allowed_signers) in +this repository. From a clone: + +```bash +git config gpg.ssh.allowedSignersFile allowed_signers +``` + +```bash +git verify-tag 3.1.5 +``` + +The signature covers the tag object, which pins the commit and therefore the +whole tree, so a good signature verifies every file at that release and no +separate tarball checksum is needed. Build a tarball from the verified tag: + +```bash +git archive --format=tar.gz --prefix=acme.sh-3.1.5/ 3.1.5 > acme.sh-3.1.5.tar.gz +``` + +> ⚠️ Tags up to `3.1.4` predate the signing key and are unsigned. + --- ### 2️⃣ Issue a Certificate diff --git a/allowed_signers b/allowed_signers new file mode 100644 index 00000000..8ed9d0a7 --- /dev/null +++ b/allowed_signers @@ -0,0 +1,20 @@ +# acme.sh release signing key. +# +# Release tags are signed with this key. Its private half is held by the +# maintainer and is never available to CI, so a compromise of the build +# pipeline cannot produce a tag that verifies against this file. +# +# Fingerprint: SHA256:M60qVafm/NUywQHXAkoQcj2v6KgkfrdSXv6mPejUUeE +# +# To verify a release tag, from a clone of this repository: +# +# git config gpg.ssh.allowedSignersFile allowed_signers +# git verify-tag 3.1.5 +# +# A good signature covers the tag object, which pins the commit, which pins +# the whole tree -- so verifying the tag verifies every file at that +# release. Build a tarball from the verified tag with: +# +# git archive --format=tar.gz --prefix=acme.sh-3.1.5/ 3.1.5 > acme.sh-3.1.5.tar.gz +# +github@neilpang.com namespaces="git" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBTjI0HBJn3uhfT2DsNcFybfAZi3ADbIacMpz1BItKdB