test(web): cover constant-time compare path in HMAC verify

Existing rejectsTamperedSignature uses len+1 sig — short-circuits in
MessageDigest.isEqual on length mismatch. Same-length tamper test
forces the byte-by-byte compare so the constant-time branch is
exercised.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-27 15:30:13 +02:00
parent 25bbd759d0
commit 73e06d8164

View File

@@ -47,4 +47,18 @@ class ArtifactDownloadTokenSignerTest {
String sig = signer.signRaw(id, pastExp);
assertThat(signer.verify(id, pastExp, sig)).isFalse();
}
/** Forces the constant-time-compare branch by flipping one char at the same length —
* exercises {@code MessageDigest.isEqual}'s byte-by-byte path, not the length short-circuit. */
@Test
void rejectsSameLengthTamperedSignature() {
var signer = new ArtifactDownloadTokenSigner(secret, clock);
UUID id = UUID.randomUUID();
var token = signer.sign(id, Duration.ofMinutes(5));
char last = token.sig().charAt(token.sig().length() - 1);
char swapped = last == 'A' ? 'B' : 'A';
String tampered = token.sig().substring(0, token.sig().length() - 1) + swapped;
assertThat(tampered).hasSameSizeAs(token.sig());
assertThat(signer.verify(id, token.exp(), tampered)).isFalse();
}
}