diff --git a/CHANGELOG.md b/CHANGELOG.md index 691aad998e..b4e3e79212 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,11 @@ Updated Motoko to [0.10.1](https://github.com/dfinity/motoko/releases/tag/0.10.1 Defining a custom `etag` header no longer breaks certification. -- Module hash: 517d5117bb43236e1673627aacec3955a68072dcd95f0b0218e6155f75a4bb54 +Fixed a certification issue where under certain conditions the fallback file (`/index.html`) was served with an incomplete certificate tree, not proving sufficiently that the fallback file may be used as a replacement. + +- Module hash: 965c8899f0a033593dc9b1634b2ab4e0f3fd28c1cfa06993069be2040a2f700e +- https://github.com/dfinity/sdk/pull/3429 +- https://github.com/dfinity/sdk/pull/3428 - https://github.com/dfinity/sdk/pull/3421 ### Replica diff --git a/Cargo.lock b/Cargo.lock index 625e18ce76..57c2d4bdb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3187,9 +3187,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -3881,9 +3881,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.57" +version = "0.10.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +checksum = "a9dfc0783362704e97ef3bd24261995a699468440099ef95d869b4d9732f829a" dependencies = [ "bitflags 2.4.1", "cfg-if 1.0.0", @@ -3922,9 +3922,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.93" +version = "0.9.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +checksum = "2f55da20b29f956fb01f0add8683eb26ee13ebe3ebd935e49898717c6b4b2830" dependencies = [ "cc", "libc", @@ -6051,9 +6051,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -6061,9 +6061,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", @@ -6076,9 +6076,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -6088,9 +6088,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6098,9 +6098,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", @@ -6111,9 +6111,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "wasm-encoder" @@ -6185,9 +6185,9 @@ checksum = "449167e2832691a1bff24cde28d2804e90e09586a448c8e76984792c44334a6b" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/src/canisters/frontend/ic-certified-assets/src/asset_certification/mod.rs b/src/canisters/frontend/ic-certified-assets/src/asset_certification/mod.rs index 42b731fd05..2ee8f5eac7 100644 --- a/src/canisters/frontend/ic-certified-assets/src/asset_certification/mod.rs +++ b/src/canisters/frontend/ic-certified-assets/src/asset_certification/mod.rs @@ -184,25 +184,18 @@ impl CertifiedResponses { WitnessResult::PathFound, ) } else { - let fallback_path = HashTreePath::not_found_base_path_v2(); - let absence_proof = self.witness(hash_tree_path_root.as_vec()); - let fallback_trailing_slash_path = HashTreePath::not_found_trailing_slash_path_v2(); - let not_found_trailing_slash_proof = - self.witness(fallback_trailing_slash_path.as_vec()); - let mut combined_proof = - merge_hash_trees(absence_proof, not_found_trailing_slash_proof); - - let mut partial_path = hash_tree_path_root.0; - while partial_path.pop().is_some() && !partial_path.is_empty() { - partial_path.push(NestedTreeKey::String("<*>".into())); + let fallback_paths = hash_tree_path_root.fallback_paths_v2(); - let proof = self.witness(HashTreePath::from(partial_path.clone()).as_vec()); - combined_proof = merge_hash_trees(combined_proof, proof); - - partial_path.pop(); // remove <*> - } + let combined_proof = + fallback_paths + .into_iter() + .fold(absence_proof, |accumulator, path| { + let new_proof = self.witness(path.as_vec()); + merge_hash_trees(accumulator, new_proof) + }); + let fallback_path = HashTreePath::not_found_base_path_v2(); if self.contains_path(fallback_path.as_vec()) { (combined_proof, WitnessResult::FallbackFound) } else { diff --git a/src/canisters/frontend/ic-certified-assets/src/asset_certification/types/certification.rs b/src/canisters/frontend/ic-certified-assets/src/asset_certification/types/certification.rs index 807f7a5e0b..209dee8b74 100644 --- a/src/canisters/frontend/ic-certified-assets/src/asset_certification/types/certification.rs +++ b/src/canisters/frontend/ic-certified-assets/src/asset_certification/types/certification.rs @@ -145,6 +145,28 @@ impl HashTreePath { base64::encode(cbor) } + /// Produces all `HashTreePath`s required to prove + /// - whether or not fallback file exists and + /// - that there is no fallback file with higher priority + /// in the hash tree. + pub fn fallback_paths_v2(&self) -> Vec { + let mut paths = Vec::new(); + + // starting at 1 because "http_expr" is always the starting element + for i in 1..self.0.len() { + let mut without_trailing_slash: Vec = self.0.as_slice()[0..i].into(); + let mut with_trailing_slash = without_trailing_slash.clone(); + without_trailing_slash.push("<*>".into()); + with_trailing_slash.push("".into()); + with_trailing_slash.push("<*>".into()); + + paths.push(without_trailing_slash.into()); + paths.push(with_trailing_slash.into()); + } + + paths + } + pub fn new( asset: &str, status_code: u16, @@ -182,14 +204,6 @@ impl HashTreePath { ])) } - pub fn not_found_trailing_slash_path_v2() -> Self { - HashTreePath::from(Vec::from([ - NestedTreeKey::String("http_expr".into()), - NestedTreeKey::String("".into()), - NestedTreeKey::String("<*>".into()), - ])) - } - pub fn not_found_base_path_v1() -> Self { let not_found_path = AssetPath::from(FALLBACK_FILE); not_found_path.asset_hash_path_v1() diff --git a/src/canisters/frontend/ic-certified-assets/src/tests.rs b/src/canisters/frontend/ic-certified-assets/src/tests.rs index ad728e73ea..88fb797277 100644 --- a/src/canisters/frontend/ic-certified-assets/src/tests.rs +++ b/src/canisters/frontend/ic-certified-assets/src/tests.rs @@ -84,7 +84,17 @@ pub fn verify_response( fn certified_http_request(state: &State, request: HttpRequest) -> HttpResponse { let response = state.http_request(request.clone(), &[], unused_callback()); - assert!(verify_response(state, &request, &response).expect("Certificate validation failed.")); + match verify_response(state, &request, &response) { + Err(err) => panic!( + "Response verification failed with error {:?}. Response: {:#?}", + err, response + ), + Ok(success) => { + if !success { + panic!("Response verification failed. Response: {:?}", response) + } + } + } response } @@ -510,6 +520,8 @@ fn serve_fallback_v2() { vec![ AssetBuilder::new("/index.html", "text/html") .with_encoding("identity", vec![INDEX_BODY]), + AssetBuilder::new("/deep/nested/folder/index.html", "text/html") + .with_encoding("identity", vec![OTHER_BODY]), AssetBuilder::new("/deep/nested/folder/a_file.html", "text/html") .with_encoding("identity", vec![OTHER_BODY]), AssetBuilder::new("/deep/nested/sibling/another_file.html", "text/html") diff --git a/src/distributed/assetstorage.wasm.gz b/src/distributed/assetstorage.wasm.gz index c28925d97c..77024d108d 100755 Binary files a/src/distributed/assetstorage.wasm.gz and b/src/distributed/assetstorage.wasm.gz differ