diff --git a/corpus/native-protected-boundaries/README.md b/corpus/native-protected-boundaries/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e45118c5733909412024acf32b83041f8f1a9cba --- /dev/null +++ b/corpus/native-protected-boundaries/README.md @@ -0,0 +1,20 @@ +# Native protected attachment boundaries + +Synthetic OneNote 2010 section with an exact known password in +[manifest.json](manifest.json), including a supplementary Unicode character and a +combining mark. All pages and attachments were generated by native OneNote. +[The generator](../../tools/native/external-assets.ps1) accepts the recorded lengths. + +The notebook is the native protected image. `read/` contains an independent +fresh-clone, empty-cache unlock oracle. Its `environment.json` says `cold: false` +because the read reused the cache that the preceding isolated cold-open and +unlock step established; that step is recorded separately in the manifest. + +Attachment plaintext is reproducible: repeat the 1024-byte block whose byte at +index `i` is `i % 251`, truncated to the recorded length. Native exported hashes +are in `read/payloads.json`; no second copy of those generated bytes is retained. +The zero-length attachment has a zero-length stored payload even when protected. + +The initially rejected UI attempt is excluded. Source notebooks and personal +profiles were never edited. This fixture establishes native 2010 behavior for +these inputs; its password and contents are deliberately public. diff --git a/corpus/native-protected-boundaries/manifest.json b/corpus/native-protected-boundaries/manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..410335e16225a63efea46b167a61e13e202763a2 --- /dev/null +++ b/corpus/native-protected-boundaries/manifest.json @@ -0,0 +1,113 @@ +{ + "captured_utc": "2026-09-08T03:41:36.733670+00:00", + "native_build": "14.0.4763.1000", + "password": "native-payloads-🦀-é", + "generator": "../../tools/native/external-assets.ps1", + "lengths": [ + 0, + 1, + 15, + 16, + 17, + 4095, + 4096, + 4097, + 65537, + 1048577 + ], + "native_pages": 11, + "operations": [ + "Native generated synthetic attachment pages; clean image retained before protection.", + "Set password in OneNote UI on owned clone; native lock and unlock passed.", + "Fresh clone and isolated native cache; observed locked section and unlocked with the exact fixture password.", + "Native cold-read returned all 11 pages; titles and text matched the pre-protection capture; every attachment matched byte for byte.", + "Both owned clones removed." + ], + "cold_cache": { + "pages": 11, + "hostname": "ONE-M6-139963EF", + "cold": true + }, + "files": [ + { + "path": "notebook/Open Notebook.onetoc2", + "bytes": 4936, + "sha256": "bc2400e03c8ae5f309ddb2a1640f54a4ed2b02127b99b7599e2899e7f399773a" + }, + { + "path": "notebook/synthetic.one", + "bytes": 1235272, + "sha256": "d490a6f6d27a79e9c726a958ab6cdc70a49a28d27fe8fdd19619d85e622619bd" + }, + { + "path": "read/environment.json", + "bytes": 165, + "sha256": "d2a40090b6074bef02f6b3267436397b37072cd792d070d237451163ec71ae0c" + }, + { + "path": "read/hierarchy.xml", + "bytes": 2597, + "sha256": "dcc0305a7d8c5d1c5873908811399b56af64200c807503c297d236cf74cb4794" + }, + { + "path": "read/page-000.xml", + "bytes": 1699, + "sha256": "88bf95c8482a696571b812bd82773442a2000d05b0dd92772316ae96485c2dfc" + }, + { + "path": "read/page-001.xml", + "bytes": 1699, + "sha256": "c83d007a3bccffd34b5e565b3e09f9f12faf84d934311be876f9c7344b0adc00" + }, + { + "path": "read/page-002.xml", + "bytes": 1703, + "sha256": "7c925ccdb1f84440afb2e7b64beaf93fad8373fad80a71e279c988ac1c7d47f0" + }, + { + "path": "read/page-003.xml", + "bytes": 1703, + "sha256": "fd31e47e9b51a2f02327c220682967d6b2b492787ddaaf1c4af36755d5913532" + }, + { + "path": "read/page-004.xml", + "bytes": 1703, + "sha256": "78b1b2f4fe7cc9ee4f8d3830e3b01e8ae1a58060833d85a33a7e7a017022d7a6" + }, + { + "path": "read/page-005.xml", + "bytes": 1711, + "sha256": "e24344d38c142b640f86ce586cdff9ff7b1fccda019253a76e246bc68cc4ec1f" + }, + { + "path": "read/page-006.xml", + "bytes": 1711, + "sha256": "33e0703d598f63fa6caa2c13429a3a33c7930b1cc5fd84d808f2ade8e8782297" + }, + { + "path": "read/page-007.xml", + "bytes": 1711, + "sha256": "e2c1d3efebba92924533c00f8c1f071c81b4a834e494138c4a26640f7f825c49" + }, + { + "path": "read/page-008.xml", + "bytes": 1715, + "sha256": "73b09d4378e5d31faf07303085a0d2e127f878b35ada88ec6c4d26caa8ef4993" + }, + { + "path": "read/page-009.xml", + "bytes": 1723, + "sha256": "2c06ec16c7f5933d471df036ea4238254e6f537f92c5187f5cb854e45c4f8e3f" + }, + { + "path": "read/page-010.xml", + "bytes": 1235, + "sha256": "54f597866ce44693af9f947f7a2f226c06b326b35f420422083e453d1d6eab6a" + }, + { + "path": "read/payloads.json", + "bytes": 3280, + "sha256": "cfbb46f2a69ad78acf9459826456d23b0c008b8920919a2ccf938df36d4b5701" + } + ] +} diff --git a/corpus/native-protected-boundaries/notebook/Open Notebook.onetoc2 b/corpus/native-protected-boundaries/notebook/Open Notebook.onetoc2 new file mode 100644 index 0000000000000000000000000000000000000000..26949b307d50fd81e89349e2ffbf15b27898bf6e Binary files /dev/null and b/corpus/native-protected-boundaries/notebook/Open Notebook.onetoc2 differ diff --git a/corpus/native-protected-boundaries/notebook/synthetic.one b/corpus/native-protected-boundaries/notebook/synthetic.one new file mode 100644 index 0000000000000000000000000000000000000000..798ee1d0f1dff352a7602cf1c544744a3525e469 Binary files /dev/null and b/corpus/native-protected-boundaries/notebook/synthetic.one differ diff --git a/corpus/native-protected-boundaries/read/environment.json b/corpus/native-protected-boundaries/read/environment.json new file mode 100644 index 0000000000000000000000000000000000000000..4677c0fd9e2d94f924a53259789aba82b7d6dd95 --- /dev/null +++ b/corpus/native-protected-boundaries/read/environment.json @@ -0,0 +1,7 @@ +{ + "powershell": "5.1.14409.1005", + "schema": "xs2010", + "hostname": "ONE-M6-139963EF", + "cold": false, + "onenote": "14.0.4763.1000" +} diff --git a/corpus/native-protected-boundaries/read/hierarchy.xml b/corpus/native-protected-boundaries/read/hierarchy.xml new file mode 100644 index 0000000000000000000000000000000000000000..70874a962ab127bf23c44ab28aa08441cc4bef33 --- /dev/null +++ b/corpus/native-protected-boundaries/read/hierarchy.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/native-protected-boundaries/read/page-000.xml b/corpus/native-protected-boundaries/read/page-000.xml new file mode 100644 index 0000000000000000000000000000000000000000..2be7829609d2b467f47723bf1c36209c15f6619b --- /dev/null +++ b/corpus/native-protected-boundaries/read/page-000.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/native-protected-boundaries/read/page-001.xml b/corpus/native-protected-boundaries/read/page-001.xml new file mode 100644 index 0000000000000000000000000000000000000000..08f6b1710de0c19774ce1ee3157443a211ad71fc --- /dev/null +++ b/corpus/native-protected-boundaries/read/page-001.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/native-protected-boundaries/read/page-002.xml b/corpus/native-protected-boundaries/read/page-002.xml new file mode 100644 index 0000000000000000000000000000000000000000..7402d944b4efc3122cc24cd56d474c3093f32ddd --- /dev/null +++ b/corpus/native-protected-boundaries/read/page-002.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/native-protected-boundaries/read/page-003.xml b/corpus/native-protected-boundaries/read/page-003.xml new file mode 100644 index 0000000000000000000000000000000000000000..8280934011f002963d898564374cb8ae4c44cfe3 --- /dev/null +++ b/corpus/native-protected-boundaries/read/page-003.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/native-protected-boundaries/read/page-004.xml b/corpus/native-protected-boundaries/read/page-004.xml new file mode 100644 index 0000000000000000000000000000000000000000..cad0c3b55a9825fad71fa9bf4d91a24ccfb076fc --- /dev/null +++ b/corpus/native-protected-boundaries/read/page-004.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/native-protected-boundaries/read/page-005.xml b/corpus/native-protected-boundaries/read/page-005.xml new file mode 100644 index 0000000000000000000000000000000000000000..f215c5fd5b2d7171fe034b9ab23cbf83a37e5b0a --- /dev/null +++ b/corpus/native-protected-boundaries/read/page-005.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/native-protected-boundaries/read/page-006.xml b/corpus/native-protected-boundaries/read/page-006.xml new file mode 100644 index 0000000000000000000000000000000000000000..2ee987370ac710518b3617181352e639a0a380c4 --- /dev/null +++ b/corpus/native-protected-boundaries/read/page-006.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/native-protected-boundaries/read/page-007.xml b/corpus/native-protected-boundaries/read/page-007.xml new file mode 100644 index 0000000000000000000000000000000000000000..9b791699877156f8f6c93192c17609812541832a --- /dev/null +++ b/corpus/native-protected-boundaries/read/page-007.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/native-protected-boundaries/read/page-008.xml b/corpus/native-protected-boundaries/read/page-008.xml new file mode 100644 index 0000000000000000000000000000000000000000..7287b96ebc2c6c0b67481fa3e185d7523dc5875c --- /dev/null +++ b/corpus/native-protected-boundaries/read/page-008.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/native-protected-boundaries/read/page-009.xml b/corpus/native-protected-boundaries/read/page-009.xml new file mode 100644 index 0000000000000000000000000000000000000000..fcd1a97a88622f061af0b8fe289efbca84f8ade6 --- /dev/null +++ b/corpus/native-protected-boundaries/read/page-009.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/native-protected-boundaries/read/page-010.xml b/corpus/native-protected-boundaries/read/page-010.xml new file mode 100644 index 0000000000000000000000000000000000000000..508998cce55ffe2ef27dfd50895b93196071856e --- /dev/null +++ b/corpus/native-protected-boundaries/read/page-010.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/native-protected-boundaries/read/payloads.json b/corpus/native-protected-boundaries/read/payloads.json new file mode 100644 index 0000000000000000000000000000000000000000..d7c8f39c63fc29c2b9fbe1197d07cc7c19ce8cfd --- /dev/null +++ b/corpus/native-protected-boundaries/read/payloads.json @@ -0,0 +1,82 @@ +[ + { + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "name": "0.bin", + "object": "{0B7E4970-D3E3-01A1-25E0-745DEE575203}{19}{B0}", + "kind": "InsertedFile", + "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{12}{B0}", + "bytes": 0 + }, + { + "sha256": "6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d", + "name": "1.bin", + "object": "{89F9F232-AB92-07AB-39A0-579A47A5F10A}{19}{B0}", + "kind": "InsertedFile", + "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{15}{B0}", + "bytes": 1 + }, + { + "sha256": "7071fc3188fde7e7e500d4768f1784bede1a22e991648dcab9dc3219acff1d4c", + "name": "15.bin", + "object": "{A5CFC542-F990-057E-367A-028A57D773EA}{19}{B0}", + "kind": "InsertedFile", + "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{18}{B0}", + "bytes": 15 + }, + { + "sha256": "be45cb2605bf36bebde684841a28f0fd43c69850a3dce5fedba69928ee3a8991", + "name": "16.bin", + "object": "{D01E8920-2805-0083-3721-95BCC8E4167F}{19}{B0}", + "kind": "InsertedFile", + "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{21}{B0}", + "bytes": 16 + }, + { + "sha256": "3e5718fea51a8f3f5baca61c77afab473c1810f8b9db330273b4011ce92c787e", + "name": "17.bin", + "object": "{97C3EBA8-DDD3-0A4F-1E9C-683127C71288}{19}{B0}", + "kind": "InsertedFile", + "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{24}{B0}", + "bytes": 17 + }, + { + "sha256": "925128da639768d0475745fe9a9f64762cde4124250d33eeadfa3fa59ade26ba", + "name": "4095.bin", + "object": "{741633FC-036D-0C74-320F-8ADC38E0A19E}{19}{B0}", + "kind": "InsertedFile", + "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{27}{B0}", + "bytes": 4095 + }, + { + "sha256": "d836371f66ce824353fbe3fbcee019fd534c02e3afaf4266d6dacb424acb5ac1", + "name": "4096.bin", + "object": "{221F2011-02E3-0DFF-30DA-32B887343A0E}{19}{B0}", + "kind": "InsertedFile", + "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{30}{B0}", + "bytes": 4096 + }, + { + "sha256": "e17ccd8f53701462eeb137b59b9f839b0f1da9b5ed8721ac65540eff10965c91", + "name": "4097.bin", + "object": "{6FC97252-6851-027D-2C2F-02DD4D1043A5}{19}{B0}", + "kind": "InsertedFile", + "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{33}{B0}", + "bytes": 4097 + }, + { + "sha256": "dc8608b73169191bf61e580637df32af153784c4e63748134fd4ab85afcc2d40", + "name": "65537.bin", + "object": "{BB722167-561D-0EB5-282A-227BB9601E32}{19}{B0}", + "kind": "InsertedFile", + "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{36}{B0}", + "bytes": 65537 + }, + { + "sha256": "e0bf9215397fdc4f1046c58bcbab5e927b5cab719f17ac3a7312a393cd2d5d33", + "name": "1048577.bin", + "object": "{B986C7A4-513F-086A-093A-A55963EAD509}{19}{B0}", + "kind": "InsertedFile", + "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{39}{B0}", + "bytes": 1048577 + } +] \ No newline at end of file diff --git a/crates/onestore/tests/document.rs b/crates/onestore/tests/document.rs index e44ced8614d1c64700372eb7c52af03124e22eaa..997d6b84477bf30521c8a0f4b39bdb89bd7278cc 100644 --- a/crates/onestore/tests/document.rs +++ b/crates/onestore/tests/document.rs @@ -438,21 +438,25 @@ fn native_unicode_table_assets_and_coordinates_are_typed() { #[test] fn encrypted_content_is_accounted_without_fabricated_plaintext() { - let bytes = - fs::read("../../corpus/native-encrypted/encrypted-01/notebook/synthetic.one").unwrap(); - let store = Store::parse(&bytes).unwrap(); - let index = RevisionIndex::parse(&store).unwrap(); - let document = Document::parse(&index).unwrap(); - assert!(!document.spaces.is_empty()); - let nodes: Vec<_> = document - .spaces - .values() - .flat_map(|s| s.revisions.values()) - .flat_map(|r| r.nodes.values()) - .collect(); - assert!(!nodes.is_empty()); - for node in nodes { - assert!(matches!(node.kind, Kind::Encrypted { ciphertext } if !ciphertext.is_empty())); + for path in [ + "../../corpus/native-encrypted/encrypted-01/notebook/synthetic.one", + "../../corpus/native-protected-boundaries/notebook/synthetic.one", + ] { + let bytes = fs::read(path).unwrap(); + let store = Store::parse(&bytes).unwrap(); + let index = RevisionIndex::parse(&store).unwrap(); + let document = Document::parse(&index).unwrap(); + assert!(!document.spaces.is_empty()); + let nodes: Vec<_> = document + .spaces + .values() + .flat_map(|s| s.revisions.values()) + .flat_map(|r| r.nodes.values()) + .collect(); + assert!(!nodes.is_empty()); + for node in nodes { + assert!(matches!(node.kind, Kind::Encrypted { ciphertext } if !ciphertext.is_empty())); + } } } diff --git a/crates/onestore/tests/revisions.rs b/crates/onestore/tests/revisions.rs index 8d49d368c9f9146c1c4008b16e5bc4c22c4b6cf4..b282fd6a8a4c9f2fe64af3ee83ccde9563d30aa0 100644 --- a/crates/onestore/tests/revisions.rs +++ b/crates/onestore/tests/revisions.rs @@ -67,31 +67,35 @@ fn persisted_identities_preserve_native_byte_order_and_canonical_form() { #[test] fn native_encryption_remains_opaque() { - let bytes = - fs::read("../../corpus/native-encrypted/encrypted-01/notebook/synthetic.one").unwrap(); - let store = Store::parse(&bytes).unwrap(); - assert!(store.checksum_mismatches.is_empty()); - let index = RevisionIndex::parse(&store).unwrap(); - let mut encrypted = 0; - for (osid, space) in &index.spaces { - for (rid, revision) in &space.revisions { - let resolved = index.resolve(*osid, *rid).unwrap(); - if revision.encrypted { - encrypted += 1; - assert!( - resolved - .objects - .values() - .any(|object| matches!(object.data, ObjectData::Encrypted(_))) - ); - assert_eq!( - resolved.reachable().unwrap_err().message, - "Encrypted property references are unavailable" - ); + for path in [ + "../../corpus/native-encrypted/encrypted-01/notebook/synthetic.one", + "../../corpus/native-protected-boundaries/notebook/synthetic.one", + ] { + let bytes = fs::read(path).unwrap(); + let store = Store::parse(&bytes).unwrap(); + assert!(store.checksum_mismatches.is_empty()); + let index = RevisionIndex::parse(&store).unwrap(); + let mut encrypted = 0; + for (osid, space) in &index.spaces { + for (rid, revision) in &space.revisions { + let resolved = index.resolve(*osid, *rid).unwrap(); + if revision.encrypted { + encrypted += 1; + assert!( + resolved + .objects + .values() + .any(|object| matches!(object.data, ObjectData::Encrypted(_))) + ); + assert_eq!( + resolved.reachable().unwrap_err().message, + "Encrypted property references are unavailable" + ); + } } } + assert!(encrypted > 0); } - assert!(encrypted > 0); } #[test] diff --git a/crates/onestore/tests/shared_snapshot.rs b/crates/onestore/tests/shared_snapshot.rs index 2fa337a18d5e384068c67b8cb6fe9a2f345deed9..ba87504a4d63e614baf6d71eb86f48fc2a361bcf 100644 --- a/crates/onestore/tests/shared_snapshot.rs +++ b/crates/onestore/tests/shared_snapshot.rs @@ -19,6 +19,7 @@ use trace::{Event, Trace}; fn storage_inspection_preserves_opaque_images_without_claiming_edit_readiness() { for path in [ "native-encrypted/encrypted-01/notebook/synthetic.one", + "native-protected-boundaries/notebook/synthetic.one", "native-encrypted/cold-encrypted-02/notebook/Open Notebook.one", "malformed/native-inflight.one", ] {