Closes the supply-chain gap the review flagged: today the archive and its SHA-256 share one trust root (the release body), so a compromised/edited release can ship an arbitrary binary that still "verifies". This adds authenticity via a detached ed25519 signature checked against a public key PINNED IN THE BINARY (not fetched), using libsodium's crypto_sign_verify_detached. Opt-in / soft rollout: - kXmrigSignaturePublicKeyBase64 in xmrig_updater.h is EMPTY by default -> signatures are not checked and behavior is unchanged (TLS + SHA-256 only). Paste the base64 public key to enable. - Once a key is pinned, an install verifies a "<archive>.sig" asset (base64/raw 64-byte ed25519 signature over the archive bytes) when present; kXmrigRequireSignature=true additionally refuses installs that publish no signature. - The check runs after the SHA-256 check, over the same already-read archive bytes; refuses on a missing key-but-required, unreachable .sig, or invalid signature. - verifyXmrigSignature + selectXmrigSignatureAsset are pure (libsodium only) and unit-tested: valid base64 + raw-64-byte signatures verify; tampered data, wrong key, and malformed/empty inputs all fail closed. Cross-tool interop verified (Python stdlib base64 == sodium base64). - scripts/sign-xmrig-release.sh: keygen / sign / pubkey helper (PyNaCl = same libsodium ed25519) to produce the .sig assets and the public key to pin. No behavior change until a key is pinned. Both variants build; suite passes; live worker re-verified (signatures off by default). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
73 lines
2.8 KiB
Bash
Executable File
73 lines
2.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Sign DRG-XMRig release archives for the wallet's in-app updater (opt-in ed25519 signatures).
|
|
#
|
|
# The wallet verifies a detached ed25519 signature over the EXACT archive bytes against a public
|
|
# key pinned in src/util/xmrig_updater.h (kXmrigSignaturePublicKeyBase64). For each archive
|
|
# <name>.zip this produces <name>.zip.sig containing the base64 ed25519 signature — upload that
|
|
# .sig next to the .zip as a release asset.
|
|
#
|
|
# Keys are 32-byte ed25519: the secret key signs (keep OFFLINE), the public key goes in the wallet.
|
|
#
|
|
# Usage:
|
|
# scripts/sign-xmrig-release.sh keygen [out-prefix] # -> <prefix>.ed25519.{key,pub.b64}
|
|
# scripts/sign-xmrig-release.sh sign <secret.key> <file>... # -> <file>.sig per file
|
|
# scripts/sign-xmrig-release.sh pubkey <secret.key> # print the base64 public key to pin
|
|
#
|
|
# Requires python3 with PyNaCl (pip install pynacl). PyNaCl uses the same libsodium primitives the
|
|
# wallet verifies with, so signatures are guaranteed compatible.
|
|
|
|
set -euo pipefail
|
|
|
|
die() { echo "error: $*" >&2; exit 1; }
|
|
command -v python3 >/dev/null || die "python3 not found"
|
|
python3 -c 'import nacl.signing' 2>/dev/null || die "PyNaCl missing — run: pip install pynacl"
|
|
|
|
cmd="${1:-}"; shift || true
|
|
|
|
case "$cmd" in
|
|
keygen)
|
|
prefix="${1:-drg-xmrig}"
|
|
python3 - "$prefix" <<'PY'
|
|
import sys, base64, nacl.signing
|
|
prefix = sys.argv[1]
|
|
sk = nacl.signing.SigningKey.generate()
|
|
open(prefix + ".ed25519.key", "wb").write(bytes(sk))
|
|
import os; os.chmod(prefix + ".ed25519.key", 0o600)
|
|
pub_b64 = base64.standard_b64encode(bytes(sk.verify_key)).decode()
|
|
open(prefix + ".ed25519.pub.b64", "w").write(pub_b64 + "\n")
|
|
print("secret key : %s.ed25519.key (KEEP OFFLINE, mode 600)" % prefix)
|
|
print("public key : %s.ed25519.pub.b64" % prefix)
|
|
print()
|
|
print("Pin this in src/util/xmrig_updater.h (kXmrigSignaturePublicKeyBase64):")
|
|
print(" %s" % pub_b64)
|
|
PY
|
|
;;
|
|
sign)
|
|
[ $# -ge 2 ] || die "usage: sign <secret.key> <file>..."
|
|
keyfile="$1"; shift
|
|
for f in "$@"; do
|
|
[ -f "$f" ] || die "no such file: $f"
|
|
python3 - "$keyfile" "$f" <<'PY'
|
|
import sys, base64, nacl.signing
|
|
keyfile, f = sys.argv[1], sys.argv[2]
|
|
sk = nacl.signing.SigningKey(open(keyfile, "rb").read())
|
|
sig = sk.sign(open(f, "rb").read()).signature # 64-byte detached ed25519 signature
|
|
open(f + ".sig", "w").write(base64.standard_b64encode(sig).decode() + "\n")
|
|
print("signed: %s -> %s.sig" % (f, f))
|
|
PY
|
|
done
|
|
echo "Upload each .sig as a release asset next to its archive."
|
|
;;
|
|
pubkey)
|
|
[ $# -ge 1 ] || die "usage: pubkey <secret.key>"
|
|
python3 - "$1" <<'PY'
|
|
import sys, base64, nacl.signing
|
|
sk = nacl.signing.SigningKey(open(sys.argv[1], "rb").read())
|
|
print(base64.standard_b64encode(bytes(sk.verify_key)).decode())
|
|
PY
|
|
;;
|
|
*)
|
|
die "usage: $0 {keygen [prefix] | sign <secret.key> <file>... | pubkey <secret.key>}"
|
|
;;
|
|
esac
|