fix(nix-compat): accept SRI hashes of invalid length

In cl/10468, we accepted SRI hashes of invalid padding while checking
their trailing bits.

In this commit, we accept SRI hashes of invalid padding and invalid length, as Nix does.

Real world example: `pkgs.javaPackages.openjfx11.deps`
<849e4dc5ff/pkgs/development/compilers/openjdk/openjfx/11.nix (L71)>
in nixpkgs.

Change-Id: I834437e7b94dab9fbb030163f7a2741f52bbf03a
Reviewed-on: https://cl.tvl.fyi/c/depot/+/10668
Autosubmit: raitobezarius <tvl@lahfa.xyz>
Tested-by: BuildkiteCI
Reviewed-by: flokli <flokli@flokli.de>
This commit is contained in:
Ryan Lahfa 2024-01-20 02:54:50 +01:00 committed by clbot
parent a27edf6405
commit e98ea31bbd

View file

@ -237,8 +237,17 @@ pub fn from_sri_str(s: &str) -> Result<NixHash> {
// strip all padding characters.
let encoded_digest = encoded_digest.trim_end_matches('=');
if encoded_digest.len() == BASE64_NOPAD.encode_len(algo.digest_length()) {
let digest = BASE64_NOPAD
// If we are using BASE64_NOPAD, we must also disable the trailing bit checking otherwise we
// are bound to get invalid length for our inputs.
// See the `weird_sha256` example below.
let mut spec = BASE64_NOPAD.specification();
spec.check_trailing_bits = false;
let encoder = spec
.encoding()
.expect("Tvix bug: failed to get the special base64 encoder for Nix SRI hashes");
if encoded_digest.len() == encoder.encode_len(algo.digest_length()) {
let digest = encoder
.decode(encoded_digest.as_bytes())
.map_err(Error::InvalidBase64Encoding)?;
@ -493,4 +502,29 @@ mod tests {
// not passing SRI, but hash algo out of band should fail
nixhash::from_str(broken_base64, Some("sha256")).expect_err("must fail");
}
/// As we decided to pass our hashes by trimming `=` completely,
/// we need to take into account hashes with padding requirements which
/// contains trailing bits which would be checked by `BASE64_NOPAD` and would
/// make the verification crash.
///
/// This base64 has a trailing non-zero bit at bit 42.
#[test]
fn sha256_weird_base64() {
let weird_base64 = "syceJMUEknBDCHK8eGs6rUU3IQn+HnQfURfCrDxYPa9=";
let expected_digest =
hex!("b3271e24c5049270430872bc786b3aad45372109fe1e741f5117c2ac3c583daf");
let nix_hash = nixhash::from_str(&format!("sha256-{}", &weird_base64), Some("sha256"))
.expect("must succeed");
assert_eq!(&expected_digest, &nix_hash.digest_as_bytes());
// not passing hash algo out of band should succeed
let nix_hash =
nixhash::from_str(&format!("sha256-{}", &weird_base64), None).expect("must succeed");
assert_eq!(&expected_digest, &nix_hash.digest_as_bytes());
// not passing SRI, but hash algo out of band should fail
nixhash::from_str(weird_base64, Some("sha256")).expect_err("must fail");
}
}