diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/Checksum.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/Checksum.java index 09b3aeea884ac0..2f6db1497d9538 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/Checksum.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/Checksum.java @@ -34,18 +34,26 @@ private InvalidChecksumException(String msg) { private final KeyType keyType; private final HashCode hashCode; + private final boolean useSubresourceIntegrity; - private Checksum(KeyType keyType, HashCode hashCode) { + private Checksum(KeyType keyType, HashCode hashCode, boolean useSubresourceIntegrity) { this.keyType = keyType; this.hashCode = hashCode; + this.useSubresourceIntegrity = useSubresourceIntegrity; } /** Constructs a new Checksum for a given key type and hash, in hex format. */ public static Checksum fromString(KeyType keyType, String hash) throws InvalidChecksumException { + return fromString(keyType, hash, /* useSubresourceIntegrity= */ false); + } + + private static Checksum fromString(KeyType keyType, String hash, boolean useSubresourceIntegrity) + throws InvalidChecksumException { if (!keyType.isValid(hash)) { throw new InvalidChecksumException(keyType, hash); } - return new Checksum(keyType, HashCode.fromString(Ascii.toLowerCase(hash))); + return new Checksum( + keyType, HashCode.fromString(Ascii.toLowerCase(hash)), useSubresourceIntegrity); } /** Constructs a new Checksum from a hash in Subresource Integrity format. */ @@ -89,14 +97,19 @@ public static Checksum fromSubresourceIntegrity(String integrity) "Invalid " + keyType + " SRI checksum '" + integrity + "'"); } - return Checksum.fromString(keyType, HashCode.fromBytes(hash).toString()); + return Checksum.fromString( + keyType, HashCode.fromBytes(hash).toString(), /* useSubresourceIntegrity= */ true); } - public String toSubresourceIntegrity() { + private static String toSubresourceIntegrity(KeyType keyType, HashCode hashCode) { String encoded = Base64.getEncoder().encodeToString(hashCode.asBytes()); return keyType.getHashName() + "-" + encoded; } + public String toSubresourceIntegrity() { + return toSubresourceIntegrity(keyType, hashCode); + } + @Override public String toString() { return hashCode.toString(); @@ -109,4 +122,12 @@ public HashCode getHashCode() { public KeyType getKeyType() { return keyType; } + + public String emitOtherHashInSameFormat(HashCode otherHash) { + if (useSubresourceIntegrity) { + return toSubresourceIntegrity(keyType, otherHash); + } else { + return otherHash.toString(); + } + } } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/HashInputStream.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/HashInputStream.java index 51695a52187b00..f8b8cf765d6524 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/HashInputStream.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/HashInputStream.java @@ -37,13 +37,13 @@ final class HashInputStream extends InputStream { private final InputStream delegate; private final Hasher hasher; - private final HashCode code; + private final Checksum checksum; @Nullable private volatile HashCode actual; HashInputStream(@WillCloseWhenClosed InputStream delegate, Checksum checksum) { this.delegate = delegate; this.hasher = checksum.getKeyType().newHasher(); - this.code = checksum.getHashCode(); + this.checksum = checksum; } @Override @@ -83,9 +83,12 @@ private void check() throws IOException { if (actual == null) { actual = hasher.hash(); } - if (!code.equals(actual)) { + if (!checksum.getHashCode().equals(actual)) { throw new UnrecoverableHttpException( - String.format("Checksum was %s but wanted %s", actual, code)); + String.format( + "Checksum was %s but wanted %s", + checksum.emitOtherHashInSameFormat(actual), + checksum.emitOtherHashInSameFormat(checksum.getHashCode()))); } } } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/HashOutputStream.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/HashOutputStream.java index 9235fc73af48c8..a79be39fc9261c 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/HashOutputStream.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/HashOutputStream.java @@ -39,13 +39,13 @@ public final class HashOutputStream extends OutputStream { private final OutputStream delegate; private final Hasher hasher; - private final HashCode code; + private final Checksum checksum; @Nullable private volatile HashCode actual; public HashOutputStream(@WillCloseWhenClosed OutputStream delegate, Checksum checksum) { this.delegate = delegate; this.hasher = checksum.getKeyType().newHasher(); - this.code = checksum.getHashCode(); + this.checksum = checksum; } @Override @@ -81,9 +81,12 @@ private void check() throws IOException { if (actual == null) { actual = hasher.hash(); } - if (!code.equals(actual)) { + if (!checksum.getHashCode().equals(actual)) { throw new UnrecoverableHttpException( - String.format("Checksum was %s but wanted %s", actual, code)); + String.format( + "Checksum was %s but wanted %s", + checksum.emitOtherHashInSameFormat(actual), + checksum.emitOtherHashInSameFormat(checksum.getHashCode()))); } } } diff --git a/src/test/shell/bazel/external_integration_test.sh b/src/test/shell/bazel/external_integration_test.sh index 5cf80e7cca7621..83223138173ed7 100755 --- a/src/test/shell/bazel/external_integration_test.sh +++ b/src/test/shell/bazel/external_integration_test.sh @@ -1104,6 +1104,7 @@ function test_integrity_incorrect() { create_workspace_with_default_repos WORKSPACE touch BUILD zip -r repo.zip * + integrity="sha256-$(cat repo.zip | openssl dgst -sha256 -binary | openssl base64 -A)" startup_server $PWD cd - @@ -1118,7 +1119,7 @@ EOF bazel build @repo//... &> $TEST_log 2>&1 && fail "Expected to fail" expect_log "Error downloading \\[http://127.0.0.1:$fileserver_port/repo.zip\\] to" # Bazel translates the integrity value back to the sha256 checksum. - expect_log "but wanted 61a6f762aaf60652cbf332879b8dcc2cfd81be2129a061da957d039eae77f0b0" + expect_log "Checksum was $integrity but wanted sha256-Yab3Yqr2BlLL8zKHm43MLP2BviEpoGHalX0Dnq538LA=" shutdown_server } diff --git a/src/test/shell/bazel/external_patching_test.sh b/src/test/shell/bazel/external_patching_test.sh index 257b45cd8bebbe..1e336d02cb5094 100755 --- a/src/test/shell/bazel/external_patching_test.sh +++ b/src/test/shell/bazel/external_patching_test.sh @@ -291,7 +291,7 @@ EOF bazel build @ext//... &> $TEST_log 2>&1 && fail "Expected to fail" expect_log "Error downloading \\[.*/remote.patch\\] to" - expect_log "but wanted 61a6f762aaf60652cbf332879b8dcc2cfd81be2129a061da957d039eae77f0b0" + expect_log "but wanted sha256-Yab3Yqr2BlLL8zKHm43MLP2BviEpoGHalX0Dnq538LA=" } test_remote_patches_with_same_base_name() {