diff options
author | Ryan Lahfa <tvl@lahfa.xyz> | 2024-01-20T01·54+0100 |
---|---|---|
committer | clbot <clbot@tvl.fyi> | 2024-01-20T17·14+0000 |
commit | e98ea31bbd17e71566d56810fa9c1d08960461ad (patch) | |
tree | 178b2a33746fe565b1ff38697fcee47ebdee08ad /tvix/nix-compat/src/nixhash/mod.rs | |
parent | a27edf6405070a37b959572e20a0fa28a7a71a33 (diff) |
fix(nix-compat): accept SRI hashes of invalid length r/7429
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` <https://github.com/NixOS/nixpkgs/blob/849e4dc5ff0ae70fb7a0df19dbbf633e408c0f32/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>
Diffstat (limited to 'tvix/nix-compat/src/nixhash/mod.rs')
-rw-r--r-- | tvix/nix-compat/src/nixhash/mod.rs | 38 |
1 files changed, 36 insertions, 2 deletions
diff --git a/tvix/nix-compat/src/nixhash/mod.rs b/tvix/nix-compat/src/nixhash/mod.rs index 91f47ecc6320..e148eb72ee9c 100644 --- a/tvix/nix-compat/src/nixhash/mod.rs +++ b/tvix/nix-compat/src/nixhash/mod.rs @@ -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"); + } } |