feat(mining): pin xmrig release-signing key + fix raw-signature parsing bug
- Pin the ed25519 public key in xmrig_updater.h, activating signature verification in soft mode (kXmrigRequireSignature=false): a release's ".sig" asset is verified when present, but an unsigned release still installs on TLS + SHA-256. Verified live against the current release (v6.25.2, which ships no .sig yet) — still installs. - gitignore *.ed25519.key / *.ed25519.pub.b64 so a signing secret key can never be committed. - Add a unit test that the pinned key decodes to a valid 32-byte ed25519 key (a malformed paste fails the build, not silently disabling verification). Bug fix (found via a flaky test): verifyXmrigSignature trimmed trailing whitespace BEFORE the raw-64-byte check, so a raw signature whose last byte equals '\n'/'\r'/space/tab (~1.6% of signatures) was corrupted and rejected. Now base64 is tried first (safe to trim) and the raw path uses the exact untrimmed bytes. Added a deterministic regression test that forces a whitespace-terminated raw signature. Suite is stable (0 failures in 10 runs; was ~3/8). Also de-brittled the live integration test: it no longer pins a release-specific binary hash (reaching Done already means the worker verified the binary against the release's own checksum). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -178,18 +178,23 @@ bool verifyXmrigSignature(const std::string& data,
|
||||
unsigned char pubKey[crypto_sign_PUBLICKEYBYTES];
|
||||
if (!base64ToFixed(pubKeyBase64, pubKey, sizeof(pubKey))) return false;
|
||||
|
||||
// Trim the signature content; accept either base64 or a raw 64-byte signature.
|
||||
std::string sigText = signatureFileContent;
|
||||
while (!sigText.empty() &&
|
||||
(sigText.back() == '\n' || sigText.back() == '\r' ||
|
||||
sigText.back() == ' ' || sigText.back() == '\t'))
|
||||
sigText.pop_back();
|
||||
// Accept either base64 (what the .sig assets contain) or a raw 64-byte signature. Try base64
|
||||
// first on whitespace-trimmed text; only if that fails fall back to RAW bytes, using the EXACT
|
||||
// untrimmed content — so a raw signature byte that happens to equal a whitespace value (~1.6% of
|
||||
// random signatures end in one) is never stripped/corrupted. A raw 64-byte input can't be
|
||||
// mistaken for base64: 64 base64 chars decode to 48 bytes, never 64, so base64ToFixed rejects it.
|
||||
std::string trimmed = signatureFileContent;
|
||||
while (!trimmed.empty() &&
|
||||
(trimmed.back() == '\n' || trimmed.back() == '\r' ||
|
||||
trimmed.back() == ' ' || trimmed.back() == '\t'))
|
||||
trimmed.pop_back();
|
||||
|
||||
unsigned char sig[crypto_sign_BYTES];
|
||||
if (sigText.size() == crypto_sign_BYTES) {
|
||||
std::memcpy(sig, sigText.data(), crypto_sign_BYTES);
|
||||
} else if (!base64ToFixed(sigText, sig, sizeof(sig))) {
|
||||
return false;
|
||||
if (!base64ToFixed(trimmed, sig, sizeof(sig))) {
|
||||
if (signatureFileContent.size() == crypto_sign_BYTES)
|
||||
std::memcpy(sig, signatureFileContent.data(), crypto_sign_BYTES);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
return crypto_sign_verify_detached(
|
||||
|
||||
Reference in New Issue
Block a user