diff --git a/Cargo.lock b/Cargo.lock index e14762064..e69dd133d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -556,16 +556,16 @@ dependencies = [ [[package]] name = "clww-ore" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b95747f5724666cb973b2ca0659e10b6083c11f99877c4727b4c9f534a591c74" +checksum = "9527fcb65fbebc5a8f8987063c171bb37bb37fb628de1293e07c1b6e0a21a24f" dependencies = [ "blake3", "hex", "subtle", "thiserror 1.0.69", "vitaminc-ore", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", "zeroize", ] @@ -1519,7 +1519,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2 0.6.5", "tokio", "tower-service", "tracing", @@ -2299,9 +2299,9 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "ore-rs" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd65962ec1409c09d20e1e016f4fe1b4ae2e2e58dba38c155538b2c0801a185" +checksum = "b274b7a0bf081d51815ccc7b20fa3b023e5769e3446fe4de1e8e8044a4413201" dependencies = [ "aes", "block-modes", @@ -2311,12 +2311,12 @@ dependencies = [ "rand 0.10.1", "subtle-ng", "thiserror 1.0.69", - "vitaminc-context 0.8.0", + "vitaminc-context 0.9.0", "vitaminc-hmac", "vitaminc-ore", "vitaminc-prf", - "vitaminc-protected 0.8.0", - "vitaminc-random 0.8.0", + "vitaminc-protected 0.9.1", + "vitaminc-random 0.9.0", "zeroize", ] @@ -2542,7 +2542,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.5.10", + "socket2 0.6.5", "thiserror 2.0.18", "tokio", "tracing", @@ -2581,7 +2581,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.10", + "socket2 0.6.5", "tracing", "windows-sys 0.52.0", ] @@ -3361,8 +3361,8 @@ dependencies = [ "tracing-subscriber", "url", "uuid", - "vitaminc 0.8.0", - "vitaminc-protected 0.8.0", + "vitaminc 0.9.0", + "vitaminc-protected 0.9.1", "web-time", "zeroize", "zerokms-protocol", @@ -3384,7 +3384,7 @@ dependencies = [ "tempfile", "tokio", "url", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", "zeroize", ] @@ -3433,15 +3433,15 @@ dependencies = [ "tokio", "trybuild", "uuid", - "vitaminc 0.8.0", - "vitaminc-aead 0.8.0", + "vitaminc 0.9.0", + "vitaminc-aead 0.9.0", "vitaminc-aead-frame", - "vitaminc-encrypt 0.8.0", + "vitaminc-encrypt 0.9.0", "vitaminc-hmac", "vitaminc-normalize", "vitaminc-ore", "vitaminc-prf", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", "zeroize", "zerokms-protocol", ] @@ -3467,9 +3467,9 @@ dependencies = [ "proptest", "serde_json", "thiserror 1.0.69", - "vitaminc-aead 0.8.0", + "vitaminc-aead 0.9.0", "vitaminc-aead-frame", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", "zeroize", ] @@ -3502,8 +3502,8 @@ dependencies = [ "tracing", "url", "uuid", - "vitaminc 0.8.0", - "vitaminc-protected 0.8.0", + "vitaminc 0.9.0", + "vitaminc-protected 0.9.1", "zeroize", "zerokms-protocol", ] @@ -4265,16 +4265,16 @@ dependencies = [ [[package]] name = "vitaminc" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea37168a603d605732d0bf0672586139ab91736f767d7b85e173c84dcee19054" +checksum = "e7aa53d696a9e1af61b36a60b92cc0dde7421f8f58787333d3c425a176af241c" dependencies = [ - "vitaminc-aead 0.8.0", - "vitaminc-context 0.8.0", - "vitaminc-encrypt 0.8.0", - "vitaminc-protected 0.8.0", - "vitaminc-random 0.8.0", - "vitaminc-traits 0.8.0", + "vitaminc-aead 0.9.0", + "vitaminc-context 0.9.0", + "vitaminc-encrypt 0.9.0", + "vitaminc-protected 0.9.1", + "vitaminc-random 0.9.0", + "vitaminc-traits 0.9.0", ] [[package]] @@ -4294,9 +4294,9 @@ dependencies = [ [[package]] name = "vitaminc-aead" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9bb97fd543ee6a2b168e257ec69d0d274a775b1eaa3f856b5ac2941b01891c1" +checksum = "efba1dac1efc04ffc09cba49e343e0fe656c88c32472a4206f2a6df284add33d" dependencies = [ "bytes", "chrono", @@ -4304,10 +4304,10 @@ dependencies = [ "rust_decimal", "serde", "thiserror 2.0.18", - "vitaminc-aead-derive 0.8.0", - "vitaminc-context 0.8.0", - "vitaminc-protected 0.8.0", - "vitaminc-random 0.8.0", + "vitaminc-aead-derive 0.9.0", + "vitaminc-context 0.9.0", + "vitaminc-protected 0.9.1", + "vitaminc-random 0.9.0", "zeroize", ] @@ -4324,9 +4324,9 @@ dependencies = [ [[package]] name = "vitaminc-aead-derive" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0845a44c07ddc882ed47a0e92e04fc83496220f054b589ad0cbd215c5009e5b7" +checksum = "a3c6575dac7701e578b375d16a0b693294d73847ed275c9b9962cf20c423ea10" dependencies = [ "proc-macro2", "quote", @@ -4335,13 +4335,13 @@ dependencies = [ [[package]] name = "vitaminc-aead-frame" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0299777255171712a296d59164691dc1e93d10bddaab6e248fede1790dfd2e" +checksum = "ba4a3e8a2057ce32724b0d42f71e87ee348d13c818fc54a16c443b86c4fe8d9a" dependencies = [ "serde", - "vitaminc-aead 0.8.0", - "zeroize", + "vitaminc-aead 0.9.0", + "vitaminc-protected 0.9.1", ] [[package]] @@ -4356,12 +4356,12 @@ dependencies = [ [[package]] name = "vitaminc-context" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a630079ba2d50680ee5048addd430eda30613559809dd6d383551e6d3d299826" +checksum = "5b407b3127be198a8da7d4d914c11215e1eae1b467cdf89eca8a7a296055e863" dependencies = [ "mutants", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", ] [[package]] @@ -4380,72 +4380,72 @@ dependencies = [ [[package]] name = "vitaminc-encrypt" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db45e073f92ae8ca27f8fe14270bc34c75e767559c2347098dacca95180d1ddd" +checksum = "7fa0a3493624afd1490085448d6d09d22bf061954e9ab0db08837f423db3a58d" dependencies = [ "aes-gcm", "aws-lc-rs", - "vitaminc-aead 0.8.0", - "vitaminc-protected 0.8.0", - "vitaminc-random 0.8.0", + "vitaminc-aead 0.9.0", + "vitaminc-protected 0.9.1", + "vitaminc-random 0.9.0", "zeroize", ] [[package]] name = "vitaminc-hmac" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5fa0ae8bbad85ae30fb5c91b0b72b694d59bf2c2c1e7ad799eda66fdbd67e7c" +checksum = "ada61349172294efe0a71bf2af367969b4e196437b46c20c688aaf15f692bc2d" dependencies = [ "hmac", "sha2 0.11.0", "vitaminc-prf", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", "zeroize", ] [[package]] name = "vitaminc-normalize" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5a2d8875e0b8b35b7a4f9dd698bbd13c989837cea564b5a4cbb5371b78fa937" +checksum = "f1d354f4ee3764be072eb02f4f8db79ed0ed467a7c6d9f2c6143823867bde347" dependencies = [ "thiserror 2.0.18", "unicode-general-category", "unicode-normalization", - "vitaminc-aead 0.8.0", - "vitaminc-protected 0.8.0", + "vitaminc-aead 0.9.0", + "vitaminc-protected 0.9.1", ] [[package]] name = "vitaminc-ore" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05518b4d35cb0c592dad59afb11b8e883ea252449b9ae47ff5ddeff0ed49f75" +checksum = "9a812b8e245352094c3c2113312cf86d0804b83f1e315bacd15571cd01703c8b" dependencies = [ "thiserror 2.0.18", "unicode-general-category", "unicode-normalization", - "vitaminc-aead 0.8.0", - "vitaminc-context 0.8.0", + "vitaminc-aead 0.9.0", + "vitaminc-context 0.9.0", "vitaminc-normalize", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", "zeroize", ] [[package]] name = "vitaminc-prf" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916688478273ca3e5c6805b355534ce9263688391cd4ab23b08bef760039d325" +checksum = "d1703452d837ef964ec1f20cc601265857245d72ac14426276d49c3106dd39b3" dependencies = [ "mutants", "thiserror 2.0.18", - "vitaminc-aead 0.8.0", - "vitaminc-context 0.8.0", + "vitaminc-aead 0.9.0", + "vitaminc-context 0.9.0", "vitaminc-normalize", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", ] [[package]] @@ -4467,9 +4467,9 @@ dependencies = [ [[package]] name = "vitaminc-protected" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6edc22562a9bbff0ba9704a2c43670b2c7cb1637524c045c3ba6436ed00917f" +checksum = "67a44502e43de42fbd95c12a35efbaea903eedcc7a3922fceacea93054f44485" dependencies = [ "bitvec", "digest 0.11.3", @@ -4478,7 +4478,7 @@ dependencies = [ "serde_bytes", "subtle", "thiserror 2.0.18", - "vitaminc-protected-derive 0.8.0", + "vitaminc-protected-derive 0.9.1", "zeroize", ] @@ -4495,9 +4495,9 @@ dependencies = [ [[package]] name = "vitaminc-protected-derive" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cce3a7d0ce6f57c0e82345f20e87f3737cccd3a70aec2a2ab49f68a3a5e24a" +checksum = "f4315341c559af17bd773e8b4e32125a2025d7fbe3e31cbae49120ee1dcab02e" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -4522,16 +4522,16 @@ dependencies = [ [[package]] name = "vitaminc-random" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb253f783ce6f31a55a92f5a9f0526109b8caa6a465edb94244fd344a078c11" +checksum = "71e32850b739b58a7064b50eb3db655de323f57f21c1fe74d5ccd4d308560563" dependencies = [ "chacha20", "getrandom 0.4.2", "rand 0.10.1", "thiserror 2.0.18", - "vitaminc-protected 0.8.0", - "vitaminc-random-derives 0.8.0", + "vitaminc-protected 0.9.1", + "vitaminc-random-derives 0.9.0", "zeroize", ] @@ -4548,9 +4548,9 @@ dependencies = [ [[package]] name = "vitaminc-random-derives" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0b3615936d6dded4b775856f4b0fa229d745d183f0b3754ac80035f16c27d9" +checksum = "1863fe02de3945047dc9094d3cadbde06becafa49aa95d5e475bf903c8d83981" dependencies = [ "proc-macro2", "quote", @@ -4575,17 +4575,17 @@ dependencies = [ [[package]] name = "vitaminc-traits" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9098ee4b13446ef959583ee2f3c384df571b453179104f7b4960ffddf65ee9" +checksum = "a715ef503b1b41801a6c23e9756ed3d5a1201fa632609bccfa2a7a41ab5386cf" dependencies = [ "anyhow", "bytes", "rmp-serde", "serde", "thiserror 2.0.18", - "vitaminc-protected 0.8.0", - "vitaminc-random 0.8.0", + "vitaminc-protected 0.9.1", + "vitaminc-random 0.9.0", "zeroize", ] @@ -4843,7 +4843,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d3234daee..7dec61963 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,15 +82,15 @@ cts-common = { version = "0.43.0", default-features = false } zerokms-protocol = "0.12.31" recipher = "=0.3.1" # The two order-preserving schemes Stack Encrypt's order terms encrypt -# through. Both implement vitaminc-ore's `OrderScheme` against vitaminc 0.8: +# through. Both implement vitaminc-ore's `OrderScheme` against vitaminc 0.9: # `clww-ore` (cllw-ore renamed) for CLWW ORE and OPE, and ore-rs's # `BlockOre` for block ORE, which routes a value to its 6-bit fixed-width # engine (up to ten bytes) or its chained one (wider, or variable length), # the terms EQL v4's `_ord_ore` domains store. # vitaminc is a plain dependency of both from here, not a feature. Both are # pinned exactly: a new release can change every stored order term. -clww-ore = { version = "=0.6.0", default-features = false } -ore-rs = { version = "=0.10.0", default-features = false } +clww-ore = { version = "=0.7.0", default-features = false } +ore-rs = { version = "=0.11.0", default-features = false } # External dependencies, with the suite's feature lists. base64 = "0.22.0" @@ -139,18 +139,18 @@ web-time = "1.1" zeroize = { version = "1.8.1", features = ["derive"] } # This is needed because lock_api 0.4.6 was breaking things and the branch forces the use of 0.4.12 temp-env = { git = "https://github.com/cipherstash/temp-env", branch = "main" } -vitaminc = { version = "0.8.0", features = ["random", "protected", "encrypt"] } -vitaminc-aead = "0.8.0" +vitaminc = { version = "0.9.0", features = ["random", "protected", "encrypt"] } +vitaminc-aead = "0.9.0" # The transport frame and ciphertext codec every language binding carries # across its FFI boundary. Optional in stack-encrypt (the `dynamic` feature). -vitaminc-aead-frame = "0.8.0" -vitaminc-encrypt = "0.8.0" -vitaminc-hmac = "0.8.0" +vitaminc-aead-frame = "0.9.0" +vitaminc-encrypt = "0.9.0" +vitaminc-hmac = "0.9.0" # Normalized equality terms (Unicode 16 NFC text, one integer encoding for # every width), which `vitaminc-prf`'s `normalize` feature derives over. -vitaminc-normalize = "0.8.0" +vitaminc-normalize = "0.9.0" # The text order key: the system ADR-0002's fold, pinned to Unicode 16, # which text ORE and OPE terms are derived over (ADR-0009). -vitaminc-ore = "0.8.0" -vitaminc-prf = { version = "0.8.0", features = ["normalize"] } -vitaminc-protected = "0.8.0" +vitaminc-ore = "0.9.0" +vitaminc-prf = { version = "0.9.0", features = ["normalize"] } +vitaminc-protected = "0.9.1" diff --git a/conformance/stack-encrypt/coverage.md b/conformance/stack-encrypt/coverage.md index 39b356b78..ce3f4c4f4 100644 --- a/conformance/stack-encrypt/coverage.md +++ b/conformance/stack-encrypt/coverage.md @@ -129,6 +129,18 @@ The [lifecycle contract](lifecycle-contract.md) enrolls native pending/KMS tests heap observations, guest ABI cleanup, Go cancellation/memory tests and public SDK diagnostics. New probes cover unpolled and in-flight drops, provider failure, cleanup after a late authenticated type failure, and chunk concurrency/drop. +The owned `Vec` to `Vec` conversion is enrolled under the same +requirements. The conversion's tests cover: + +- dropping a collection before it is polled +- dropping a collection while its key request is running +- one logical batch of key requests for each collection, and none for an + empty collection +- wiping the source `Vec` through its guard +- wiping the elements already decrypted, when a later element fails + +The owned conversion is a native Rust API. Go reaches batching through its +record interface, and the runtime profile covers that interface. Existing runtime/read/context vectors retain their provider-call counters. This adds required execution and explicit observation limits; it removes no diff --git a/conformance/stack-encrypt/lifecycle-contract.md b/conformance/stack-encrypt/lifecycle-contract.md index 2cf10ab12..7186846f7 100644 --- a/conformance/stack-encrypt/lifecycle-contract.md +++ b/conformance/stack-encrypt/lifecycle-contract.md @@ -10,13 +10,13 @@ process. Python and TypeScript are explicitly not enrolled. | Requirement | Native evidence | Go evidence and limits | |---|---|---| -| `lifecycle-ownership-v1` | Actual record operations release fulfilment captures exactly once on success, provider failure and unpolled drop; an unpolled encrypt or decrypt makes no key request. Zipped fulfilments do not share key material. | Client keys are consumed/redacted; explicit close and unreachable-client cleanup release guest memory; calls on a closed client fail. GC cleanup is eventual, so callers should close explicitly. | -| `lifecycle-cancellation-v1` | Dropping an encrypt future paused in key generation, or a decrypt future paused in key retrieval, drops the provider future and operation captures; subsequent work on the cipher succeeds. Guest ABI abort spends the handle and drops the operation. | Cancellation before a call sends no request; cancellation between steps or during token fetch leaves unrelated operations usable. A guest step that overruns cancellation closes the client. Discarded late output is wiped. | -| `lifecycle-partial-output-v1` | A batch with a valid first row and a later authenticated type mismatch releases its decoded prefix without marked heap residue. Existing context cases reject late authentication failures without returning partial output. | Generated and raw batch APIs return no partial rows on failure; interrupted HTTP bodies fail; cancelled output is wiped. SDK conversion diagnostics contain no decrypted values. This does not assert erasure of partially populated caller-owned Go objects. | -| `lifecycle-buffer-cleanup-v1` | The existing allocator observer checks selected write/read/JSON parse paths and has a negative control. Guest ABI tests check buffer-registry cleanup, error-buffer release and protected text drop. | Request bodies survive until their owner closes them, then wipe; refused requests wipe; heap growth wipes abandoned backing arrays; guest runtime close releases memory. Post-encryption memory scans are supplementary observations. | +| `lifecycle-ownership-v1` | Actual record operations and owned `Vec` to `Vec` conversions release fulfilment captures exactly once on success, provider failure and unpolled drop; an unpolled encrypt or decrypt makes no key request. Zipped fulfilments do not share key material. | Client keys are consumed/redacted; explicit close and unreachable-client cleanup release guest memory; calls on a closed client fail. GC cleanup is eventual, so callers should close explicitly. | +| `lifecycle-cancellation-v1` | Dropping an encrypt future paused in key generation, or a decrypt future paused in key retrieval, drops the provider future and operation captures, for a record operation or an owned collection; subsequent work on the cipher succeeds. Guest ABI abort spends the handle and drops the operation. | Cancellation before a call sends no request; cancellation between steps or during token fetch leaves unrelated operations usable. A guest step that overruns cancellation closes the client. Discarded late output is wiped. | +| `lifecycle-partial-output-v1` | A batch with a valid first row and a later authenticated type mismatch releases its decoded prefix without marked heap residue. Tests check this for the dynamic record path and for the owned `Vec` to `Vec` conversion. For owned collections, drop witnesses are test values that record whether they were wiped. They show that the prefix is wiped, not leaked, after a late failure or an element's panic. Existing context cases reject late authentication failures without returning partial output. | Generated and raw batch APIs return no partial rows on failure; interrupted HTTP bodies fail; cancelled output is wiped. SDK conversion diagnostics contain no decrypted values. This does not assert erasure of partially populated caller-owned Go objects. | +| `lifecycle-buffer-cleanup-v1` | The existing allocator observer checks selected write/read/JSON parse paths and has a negative control. One of those paths encrypts an owned `Vec` collection through its guard. Drop witnesses show that an owned collection's source is wiped before its pending request is returned. That includes a refused context, and a context conversion that panics. Guest ABI tests check buffer-registry cleanup, error-buffer release and protected text drop. | Request bodies survive until their owner closes them, then wipe; refused requests wipe; heap growth wipes abandoned backing arrays; guest runtime close releases memory. Post-encryption memory scans are supplementary observations. | | `lifecycle-diagnostics-v1` | Guest errors discard untrusted foreign cause messages; failed/successful exports do not hand over stale diagnostics. | Structured errors remain available after failures; SDK errors and redacted display/logging expose types or fields rather than plaintext values. | | `lifecycle-validation-before-io-v1` | Existing runtime/read/context cases count provider calls. Wrong shape, independently detectable context mismatch and oversized descriptors fail before key I/O; lazy assembly stops after local failure. | Host refusals happen before entering the guest, and shared runtime/read cases exercise the uninitialised guest's preflight boundary. Go does not yet expose native provider counters. | -| `lifecycle-logical-batching-v1` | Instrumented `DataKeySource` calls establish one logical generation batch, retrieval grouping by keyset, descriptor ordering and no work for empty batches. | Go uses the same engine, but this profile does not claim independently instrumented Go key-request counts. | +| `lifecycle-logical-batching-v1` | Instrumented `DataKeySource` calls establish one logical generation batch, retrieval grouping by keyset, descriptor ordering and no work for empty batches, for record operations and for an owned `Vec` collection of any length, including an empty one. | Go uses the same engine, but this profile does not claim independently instrumented Go key-request counts. | | `lifecycle-provider-chunks-v1` | The actual KMS chunking helper preserves order, handles a final short chunk, fails the whole call on a chunk error, bounds in-flight chunks and releases their futures on cancellation. | This is a native algorithm observation, not a measurement of live HTTP request counts. | The drop witnesses belong to fulfilment closures and provider futures in real @@ -59,7 +59,12 @@ These entries in the index are limitations, not successful requirements: sealing frame by backtrace and reports excluded frees. It scrubs stack residue before observing heap frees; it does not prove stack erasure. Its JSON query paths use borrowed/static path text because owned path copies have separate - cleanup limitations. The lifecycle runner preserves the observer's output. + cleanup limitations. The observer only scans blocks that are freed, so it + misses plaintext that is leaked and never freed. For the owned `Vec` + conversion, the drop witnesses in `packages/stack-encrypt/tests/collections.rs` + record the wipe itself. A test there fails if a source or a decrypted prefix + is leaked. The lifecycle + runner preserves the observer's output. - **`caller-owned-host-values` — outside the guarantee.** Caller-owned strings, bytes, objects, returned plaintext, aliases and copies remain the caller's responsibility. Ownership transfer or protected borrowing must be stated by diff --git a/conformance/stack-encrypt/v1/lifecycle-v1.enrollment.json b/conformance/stack-encrypt/v1/lifecycle-v1.enrollment.json index 12b35f883..b9a0e39d6 100644 --- a/conformance/stack-encrypt/v1/lifecycle-v1.enrollment.json +++ b/conformance/stack-encrypt/v1/lifecycle-v1.enrollment.json @@ -27,6 +27,14 @@ "binary": "heap_hygiene", "success_output": "immediate" }, + "collections": { + "language": "rust", + "lane": "fast", + "workspace": ".", + "package": "stack-encrypt", + "features": ["--all-features"], + "binary": "collections" + }, "runtime": { "language": "rust", "lane": "fast", @@ -90,7 +98,9 @@ "lifecycle": [ "dropping_unpolled_work_releases_captures_without_key_io", "dropping_unpolled_decrypt_releases_captures_without_key_io", - "success_and_provider_failure_release_captures_once" + "success_and_provider_failure_release_captures_once", + "dropping_an_unpolled_owned_column_releases_captures_without_key_io", + "an_owned_column_is_one_logical_batch_and_releases_captures_once" ], "pending": [ "target::pending::tests::zipped_fulfilments_never_share_key_material" @@ -108,7 +118,8 @@ "evidence": { "lifecycle": [ "cancelling_in_flight_work_drops_provider_and_captures", - "cancelling_in_flight_decrypt_drops_provider_and_captures" + "cancelling_in_flight_decrypt_drops_provider_and_captures", + "cancelling_an_owned_column_in_flight_drops_provider_and_captures" ], "guest-abi": [ "step::tests::an_aborted_operation_is_dropped_and_its_handle_spent", @@ -127,7 +138,14 @@ { "id": "lifecycle-partial-output-v1", "evidence": { - "heap": ["a_late_read_type_failure_leaves_no_plaintext_on_the_heap"], + "heap": [ + "a_late_read_type_failure_leaves_no_plaintext_on_the_heap", + "a_late_type_failure_in_an_owned_column_leaves_no_plaintext_on_the_heap" + ], + "collections": [ + "a_late_element_failure_wipes_the_plaintext_recovered_before_it", + "a_panicking_element_conversion_wipes_the_plaintext_recovered_before_it" + ], "contexts": ["shared_context_boundaries"], "go": [ "TestContextBoundaries", @@ -142,10 +160,16 @@ "evidence": { "heap": [ "a_record_encrypted_from_a_value_frame_leaves_no_plaintext_on_the_heap", + "an_owned_column_encrypted_leaves_no_plaintext_on_the_heap", "a_record_decrypted_with_a_nested_field_leaves_no_plaintext_on_the_heap", "a_json_document_read_from_a_frame_leaves_no_plaintext_on_the_heap", "the_spy_sees_an_unwiped_free" ], + "collections": [ + "owned_elements_are_wiped_before_the_pending_is_returned", + "owned_elements_are_wiped_when_the_context_is_refused", + "owned_elements_are_guarded_during_context_conversion" + ], "guest-abi": [ "buffers::tests::wipe_all_leaves_no_live_buffer", "last_error::tests::clearing_wipes_and_frees_the_registered_buffer", @@ -205,6 +229,10 @@ "id": "lifecycle-logical-batching-v1", "evidence": { "runtime": ["shared_record_runtime_profile"], + "lifecycle": [ + "an_owned_column_is_one_logical_batch_and_releases_captures_once", + "an_empty_owned_column_makes_no_provider_call" + ], "pending": [ "target::pending::tests::one_pending_asking_for_many_keys_is_one_call", "target::pending::tests::all_merges_a_column_into_one_call_preserving_order", diff --git a/languages/golang/auth/guest/Cargo.lock b/languages/golang/auth/guest/Cargo.lock index 95eb9372e..b8bc8eb21 100644 --- a/languages/golang/auth/guest/Cargo.lock +++ b/languages/golang/auth/guest/Cargo.lock @@ -633,7 +633,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1613,7 +1613,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1807,8 +1807,8 @@ dependencies = [ "tracing", "url", "uuid", - "vitaminc 0.8.0", - "vitaminc-protected 0.8.0", + "vitaminc 0.9.1", + "vitaminc-protected 0.9.1", "web-time", "zeroize", "zerokms-protocol", @@ -1828,7 +1828,7 @@ dependencies = [ "tempfile", "tokio", "url", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", "zeroize", ] @@ -1839,9 +1839,9 @@ dependencies = [ "miette", "serde_json", "thiserror 1.0.69", - "vitaminc-aead 0.8.0", + "vitaminc-aead 0.9.1", "vitaminc-aead-frame", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", "zeroize", ] @@ -1925,7 +1925,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix 1.1.5", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2260,16 +2260,16 @@ dependencies = [ [[package]] name = "vitaminc" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea37168a603d605732d0bf0672586139ab91736f767d7b85e173c84dcee19054" +checksum = "f849264db2d0cc82e8e17e2c4172368d4627d0d383087415a99f9b6299252f11" dependencies = [ - "vitaminc-aead 0.8.0", - "vitaminc-context 0.8.0", - "vitaminc-encrypt 0.8.0", - "vitaminc-protected 0.8.0", - "vitaminc-random 0.8.0", - "vitaminc-traits 0.8.0", + "vitaminc-aead 0.9.1", + "vitaminc-context 0.9.1", + "vitaminc-encrypt 0.9.1", + "vitaminc-protected 0.9.1", + "vitaminc-random 0.9.1", + "vitaminc-traits 0.9.1", ] [[package]] @@ -2289,18 +2289,18 @@ dependencies = [ [[package]] name = "vitaminc-aead" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9bb97fd543ee6a2b168e257ec69d0d274a775b1eaa3f856b5ac2941b01891c1" +checksum = "56725963f5e40788904814a648ad32e2a8697c9ff870699eff8d843fd4c0ee31" dependencies = [ "bytes", "futures-util", "serde", "thiserror 2.0.20", - "vitaminc-aead-derive 0.8.0", - "vitaminc-context 0.8.0", - "vitaminc-protected 0.8.0", - "vitaminc-random 0.8.0", + "vitaminc-aead-derive 0.9.1", + "vitaminc-context 0.9.1", + "vitaminc-protected 0.9.1", + "vitaminc-random 0.9.1", "zeroize", ] @@ -2317,9 +2317,9 @@ dependencies = [ [[package]] name = "vitaminc-aead-derive" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0845a44c07ddc882ed47a0e92e04fc83496220f054b589ad0cbd215c5009e5b7" +checksum = "106cba4ea0ea260d150ef3a2905b908cac8e3aebbf484d290371c3bd48cb3943" dependencies = [ "proc-macro2", "quote", @@ -2328,11 +2328,11 @@ dependencies = [ [[package]] name = "vitaminc-aead-frame" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0299777255171712a296d59164691dc1e93d10bddaab6e248fede1790dfd2e" +checksum = "5f0ee8c7746c0fd8a6efad989b0248646d32f9ce8e45c9631f8c56b760983cd8" dependencies = [ - "vitaminc-aead 0.8.0", + "vitaminc-aead 0.9.1", ] [[package]] @@ -2347,12 +2347,12 @@ dependencies = [ [[package]] name = "vitaminc-context" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a630079ba2d50680ee5048addd430eda30613559809dd6d383551e6d3d299826" +checksum = "366b12603130fe196b300d372b49196f1314a5ba94ab67e63fd0130fc319768b" dependencies = [ "mutants", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", ] [[package]] @@ -2371,15 +2371,15 @@ dependencies = [ [[package]] name = "vitaminc-encrypt" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db45e073f92ae8ca27f8fe14270bc34c75e767559c2347098dacca95180d1ddd" +checksum = "a95db3fd733fc76ee11401604d5673782a3d2f5a047b3a3f49d56ca90b027d0e" dependencies = [ "aes-gcm", "aws-lc-rs", - "vitaminc-aead 0.8.0", - "vitaminc-protected 0.8.0", - "vitaminc-random 0.8.0", + "vitaminc-aead 0.9.1", + "vitaminc-protected 0.9.1", + "vitaminc-random 0.9.1", "zeroize", ] @@ -2402,9 +2402,9 @@ dependencies = [ [[package]] name = "vitaminc-protected" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6edc22562a9bbff0ba9704a2c43670b2c7cb1637524c045c3ba6436ed00917f" +checksum = "67a44502e43de42fbd95c12a35efbaea903eedcc7a3922fceacea93054f44485" dependencies = [ "bitvec", "digest 0.11.3", @@ -2413,7 +2413,7 @@ dependencies = [ "serde_bytes", "subtle", "thiserror 2.0.20", - "vitaminc-protected-derive 0.8.0", + "vitaminc-protected-derive 0.9.1", "zeroize", ] @@ -2430,9 +2430,9 @@ dependencies = [ [[package]] name = "vitaminc-protected-derive" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cce3a7d0ce6f57c0e82345f20e87f3737cccd3a70aec2a2ab49f68a3a5e24a" +checksum = "f4315341c559af17bd773e8b4e32125a2025d7fbe3e31cbae49120ee1dcab02e" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2457,16 +2457,16 @@ dependencies = [ [[package]] name = "vitaminc-random" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb253f783ce6f31a55a92f5a9f0526109b8caa6a465edb94244fd344a078c11" +checksum = "7d08020da35051b10daddaa0f85fbb15f084723dfc4abce8c080bda24867a5a0" dependencies = [ "chacha20", "getrandom 0.4.3", "rand 0.10.3", "thiserror 2.0.20", - "vitaminc-protected 0.8.0", - "vitaminc-random-derives 0.8.0", + "vitaminc-protected 0.9.1", + "vitaminc-random-derives 0.9.1", "zeroize", ] @@ -2483,9 +2483,9 @@ dependencies = [ [[package]] name = "vitaminc-random-derives" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0b3615936d6dded4b775856f4b0fa229d745d183f0b3754ac80035f16c27d9" +checksum = "76e17e2cfead782db61ef778257853c7c5ff27ad1aee5f323b6461d9d166ee82" dependencies = [ "proc-macro2", "quote", @@ -2510,17 +2510,17 @@ dependencies = [ [[package]] name = "vitaminc-traits" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9098ee4b13446ef959583ee2f3c384df571b453179104f7b4960ffddf65ee9" +checksum = "bf1a88df9b1a6530127462338ea47a1b65b8879f8ac9123ea5b7aa5ba1c5c9fd" dependencies = [ "anyhow", "bytes", "rmp-serde", "serde", "thiserror 2.0.20", - "vitaminc-protected 0.8.0", - "vitaminc-random 0.8.0", + "vitaminc-protected 0.9.1", + "vitaminc-random 0.9.1", "zeroize", ] diff --git a/languages/golang/auth/guest/Cargo.toml b/languages/golang/auth/guest/Cargo.toml index e3fd3cca4..4db8c3855 100644 --- a/languages/golang/auth/guest/Cargo.toml +++ b/languages/golang/auth/guest/Cargo.toml @@ -50,7 +50,7 @@ tempfile = "3" # Native stack-auth refreshes run in a Tokio task, including with a mock transport. tokio = { version = "1.47.1", default-features = false, features = ["macros", "rt"] } # `Controlled::risky_ref`, to read a codec value back in the tests. -vitaminc-protected = "0.8.0" +vitaminc-protected = "0.9.1" [profile.release] # Smaller .wasm; the guest is IO-bound on the FFI copy and the file reads, diff --git a/languages/golang/encrypt/guest/Cargo.lock b/languages/golang/encrypt/guest/Cargo.lock index 81cbcb3c3..9c2cc2d59 100644 --- a/languages/golang/encrypt/guest/Cargo.lock +++ b/languages/golang/encrypt/guest/Cargo.lock @@ -357,16 +357,16 @@ dependencies = [ [[package]] name = "clww-ore" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b95747f5724666cb973b2ca0659e10b6083c11f99877c4727b4c9f534a591c74" +checksum = "9527fcb65fbebc5a8f8987063c171bb37bb37fb628de1293e07c1b6e0a21a24f" dependencies = [ "blake3", "hex", "subtle", "thiserror 1.0.69", "vitaminc-ore", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", "zeroize", ] @@ -752,7 +752,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1458,9 +1458,9 @@ dependencies = [ [[package]] name = "ore-rs" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd65962ec1409c09d20e1e016f4fe1b4ae2e2e58dba38c155538b2c0801a185" +checksum = "b274b7a0bf081d51815ccc7b20fa3b023e5769e3446fe4de1e8e8044a4413201" dependencies = [ "aes", "block-modes", @@ -1470,12 +1470,12 @@ dependencies = [ "rand 0.10.2", "subtle-ng", "thiserror 1.0.69", - "vitaminc-context 0.8.0", + "vitaminc-context 0.9.0", "vitaminc-hmac", "vitaminc-ore", "vitaminc-prf", - "vitaminc-protected 0.8.0", - "vitaminc-random 0.8.0", + "vitaminc-protected 0.9.1", + "vitaminc-random 0.9.0", "zeroize", ] @@ -2110,8 +2110,8 @@ dependencies = [ "tracing", "url", "uuid", - "vitaminc 0.8.0", - "vitaminc-protected 0.8.0", + "vitaminc 0.9.0", + "vitaminc-protected 0.9.1", "web-time", "zeroize", "zerokms-protocol", @@ -2136,15 +2136,15 @@ dependencies = [ "stack-kms", "thiserror 1.0.69", "uuid", - "vitaminc 0.8.0", - "vitaminc-aead 0.8.0", + "vitaminc 0.9.0", + "vitaminc-aead 0.9.0", "vitaminc-aead-frame", - "vitaminc-encrypt 0.8.0", + "vitaminc-encrypt 0.9.0", "vitaminc-hmac", "vitaminc-normalize", "vitaminc-ore", "vitaminc-prf", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", "zeroize", ] @@ -2184,9 +2184,9 @@ dependencies = [ "miette", "serde_json", "thiserror 1.0.69", - "vitaminc-aead 0.8.0", + "vitaminc-aead 0.9.0", "vitaminc-aead-frame", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", "zeroize", ] @@ -2212,8 +2212,8 @@ dependencies = [ "tracing", "url", "uuid", - "vitaminc 0.8.0", - "vitaminc-protected 0.8.0", + "vitaminc 0.9.0", + "vitaminc-protected 0.9.1", "zeroize", "zerokms-protocol", ] @@ -2688,16 +2688,16 @@ dependencies = [ [[package]] name = "vitaminc" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea37168a603d605732d0bf0672586139ab91736f767d7b85e173c84dcee19054" +checksum = "e7aa53d696a9e1af61b36a60b92cc0dde7421f8f58787333d3c425a176af241c" dependencies = [ - "vitaminc-aead 0.8.0", - "vitaminc-context 0.8.0", - "vitaminc-encrypt 0.8.0", - "vitaminc-protected 0.8.0", - "vitaminc-random 0.8.0", - "vitaminc-traits 0.8.0", + "vitaminc-aead 0.9.0", + "vitaminc-context 0.9.0", + "vitaminc-encrypt 0.9.0", + "vitaminc-protected 0.9.1", + "vitaminc-random 0.9.0", + "vitaminc-traits 0.9.0", ] [[package]] @@ -2717,18 +2717,18 @@ dependencies = [ [[package]] name = "vitaminc-aead" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9bb97fd543ee6a2b168e257ec69d0d274a775b1eaa3f856b5ac2941b01891c1" +checksum = "efba1dac1efc04ffc09cba49e343e0fe656c88c32472a4206f2a6df284add33d" dependencies = [ "bytes", "futures-util", "serde", "thiserror 2.0.20", - "vitaminc-aead-derive 0.8.0", - "vitaminc-context 0.8.0", - "vitaminc-protected 0.8.0", - "vitaminc-random 0.8.0", + "vitaminc-aead-derive 0.9.0", + "vitaminc-context 0.9.0", + "vitaminc-protected 0.9.1", + "vitaminc-random 0.9.0", "zeroize", ] @@ -2745,9 +2745,9 @@ dependencies = [ [[package]] name = "vitaminc-aead-derive" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0845a44c07ddc882ed47a0e92e04fc83496220f054b589ad0cbd215c5009e5b7" +checksum = "a3c6575dac7701e578b375d16a0b693294d73847ed275c9b9962cf20c423ea10" dependencies = [ "proc-macro2", "quote", @@ -2756,13 +2756,13 @@ dependencies = [ [[package]] name = "vitaminc-aead-frame" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0299777255171712a296d59164691dc1e93d10bddaab6e248fede1790dfd2e" +checksum = "ba4a3e8a2057ce32724b0d42f71e87ee348d13c818fc54a16c443b86c4fe8d9a" dependencies = [ "serde", - "vitaminc-aead 0.8.0", - "zeroize", + "vitaminc-aead 0.9.0", + "vitaminc-protected 0.9.1", ] [[package]] @@ -2777,12 +2777,12 @@ dependencies = [ [[package]] name = "vitaminc-context" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a630079ba2d50680ee5048addd430eda30613559809dd6d383551e6d3d299826" +checksum = "5b407b3127be198a8da7d4d914c11215e1eae1b467cdf89eca8a7a296055e863" dependencies = [ "mutants", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", ] [[package]] @@ -2801,72 +2801,72 @@ dependencies = [ [[package]] name = "vitaminc-encrypt" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db45e073f92ae8ca27f8fe14270bc34c75e767559c2347098dacca95180d1ddd" +checksum = "7fa0a3493624afd1490085448d6d09d22bf061954e9ab0db08837f423db3a58d" dependencies = [ "aes-gcm", "aws-lc-rs", - "vitaminc-aead 0.8.0", - "vitaminc-protected 0.8.0", - "vitaminc-random 0.8.0", + "vitaminc-aead 0.9.0", + "vitaminc-protected 0.9.1", + "vitaminc-random 0.9.0", "zeroize", ] [[package]] name = "vitaminc-hmac" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5fa0ae8bbad85ae30fb5c91b0b72b694d59bf2c2c1e7ad799eda66fdbd67e7c" +checksum = "ada61349172294efe0a71bf2af367969b4e196437b46c20c688aaf15f692bc2d" dependencies = [ "hmac", "sha2 0.11.0", "vitaminc-prf", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", "zeroize", ] [[package]] name = "vitaminc-normalize" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5a2d8875e0b8b35b7a4f9dd698bbd13c989837cea564b5a4cbb5371b78fa937" +checksum = "f1d354f4ee3764be072eb02f4f8db79ed0ed467a7c6d9f2c6143823867bde347" dependencies = [ "thiserror 2.0.20", "unicode-general-category", "unicode-normalization", - "vitaminc-aead 0.8.0", - "vitaminc-protected 0.8.0", + "vitaminc-aead 0.9.0", + "vitaminc-protected 0.9.1", ] [[package]] name = "vitaminc-ore" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05518b4d35cb0c592dad59afb11b8e883ea252449b9ae47ff5ddeff0ed49f75" +checksum = "9a812b8e245352094c3c2113312cf86d0804b83f1e315bacd15571cd01703c8b" dependencies = [ "thiserror 2.0.20", "unicode-general-category", "unicode-normalization", - "vitaminc-aead 0.8.0", - "vitaminc-context 0.8.0", + "vitaminc-aead 0.9.0", + "vitaminc-context 0.9.0", "vitaminc-normalize", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", "zeroize", ] [[package]] name = "vitaminc-prf" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916688478273ca3e5c6805b355534ce9263688391cd4ab23b08bef760039d325" +checksum = "d1703452d837ef964ec1f20cc601265857245d72ac14426276d49c3106dd39b3" dependencies = [ "mutants", "thiserror 2.0.20", - "vitaminc-aead 0.8.0", - "vitaminc-context 0.8.0", + "vitaminc-aead 0.9.0", + "vitaminc-context 0.9.0", "vitaminc-normalize", - "vitaminc-protected 0.8.0", + "vitaminc-protected 0.9.1", ] [[package]] @@ -2888,9 +2888,9 @@ dependencies = [ [[package]] name = "vitaminc-protected" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6edc22562a9bbff0ba9704a2c43670b2c7cb1637524c045c3ba6436ed00917f" +checksum = "67a44502e43de42fbd95c12a35efbaea903eedcc7a3922fceacea93054f44485" dependencies = [ "bitvec", "digest 0.11.3", @@ -2899,7 +2899,7 @@ dependencies = [ "serde_bytes", "subtle", "thiserror 2.0.20", - "vitaminc-protected-derive 0.8.0", + "vitaminc-protected-derive 0.9.1", "zeroize", ] @@ -2916,9 +2916,9 @@ dependencies = [ [[package]] name = "vitaminc-protected-derive" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cce3a7d0ce6f57c0e82345f20e87f3737cccd3a70aec2a2ab49f68a3a5e24a" +checksum = "f4315341c559af17bd773e8b4e32125a2025d7fbe3e31cbae49120ee1dcab02e" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2943,16 +2943,16 @@ dependencies = [ [[package]] name = "vitaminc-random" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb253f783ce6f31a55a92f5a9f0526109b8caa6a465edb94244fd344a078c11" +checksum = "71e32850b739b58a7064b50eb3db655de323f57f21c1fe74d5ccd4d308560563" dependencies = [ "chacha20", "getrandom 0.4.3", "rand 0.10.2", "thiserror 2.0.20", - "vitaminc-protected 0.8.0", - "vitaminc-random-derives 0.8.0", + "vitaminc-protected 0.9.1", + "vitaminc-random-derives 0.9.0", "zeroize", ] @@ -2969,9 +2969,9 @@ dependencies = [ [[package]] name = "vitaminc-random-derives" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0b3615936d6dded4b775856f4b0fa229d745d183f0b3754ac80035f16c27d9" +checksum = "1863fe02de3945047dc9094d3cadbde06becafa49aa95d5e475bf903c8d83981" dependencies = [ "proc-macro2", "quote", @@ -2996,17 +2996,17 @@ dependencies = [ [[package]] name = "vitaminc-traits" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9098ee4b13446ef959583ee2f3c384df571b453179104f7b4960ffddf65ee9" +checksum = "a715ef503b1b41801a6c23e9756ed3d5a1201fa632609bccfa2a7a41ab5386cf" dependencies = [ "anyhow", "bytes", "rmp-serde", "serde", "thiserror 2.0.20", - "vitaminc-protected 0.8.0", - "vitaminc-random 0.8.0", + "vitaminc-protected 0.9.1", + "vitaminc-random 0.9.0", "zeroize", ] @@ -3093,7 +3093,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/languages/golang/encrypt/guest/src/abi.rs b/languages/golang/encrypt/guest/src/abi.rs index fd539231b..8fad3f7af 100644 --- a/languages/golang/encrypt/guest/src/abi.rs +++ b/languages/golang/encrypt/guest/src/abi.rs @@ -90,7 +90,7 @@ use std::cell::{Cell, RefCell}; use std::panic::{catch_unwind, AssertUnwindSafe}; use std::rc::Rc; -use stack_encrypt::StackCipher; +use stack_encrypt::{Controlled as _, StackCipher}; use stack_guest_abi::abi::{export, input, take_plaintext, wipe_input}; use stack_guest_abi::buffers; use stack_guest_abi::call; @@ -99,7 +99,7 @@ use stack_guest_abi::status::STATUS_NEEDS_IO; use stack_guest_abi::step::{self, Operation, Step}; use crate::io; -use crate::ops; +use crate::ops::{self, Bytes}; use crate::options::{parse_options, parse_selector, scope_for, KeysetSelector, Side}; #[cfg(not(feature = "deterministic-kms"))] use crate::status::STATUS_INTERNAL; @@ -418,7 +418,7 @@ pub unsafe extern "C" fn se_term( let value = unsafe { take_plaintext(val_ptr, val_len)? }; // SAFETY: host-owned ranges the export was handed; the borrows end // before it returns and before any wipe of an overlapping range. - let context = unsafe { input(ctx_ptr, ctx_len)? }.to_vec(); + let context = Bytes::new(unsafe { input(ctx_ptr, ctx_len)? }.to_vec()); let opts = unsafe { input(opt_ptr, opt_len)? }; ops::validate::term(&value, &context, kind)?; let options = parse_options(opts, Side::Mint)?; @@ -453,7 +453,7 @@ pub unsafe extern "C" fn se_encrypt_record( let source = unsafe { take_plaintext(src_ptr, src_len)? }; // SAFETY: host-owned ranges the export was handed; the borrows end // before it returns and before any wipe of an overlapping range. - let plan = unsafe { input(plan_ptr, plan_len)? }.to_vec(); + let plan = Bytes::new(unsafe { input(plan_ptr, plan_len)? }.to_vec()); let opts = unsafe { input(opt_ptr, opt_len)? }; ops::validate::record(&source, &plan)?; let options = parse_options(opts, Side::Mint)?; @@ -494,7 +494,7 @@ pub unsafe extern "C" fn se_decrypt_record( // SAFETY: host-owned ranges the export was handed; the borrows end // before it returns and before any wipe of an overlapping range. let record = unsafe { input(rec_ptr, rec_len)? }.to_vec(); - let plan = unsafe { input(plan_ptr, plan_len)? }.to_vec(); + let plan = Bytes::new(unsafe { input(plan_ptr, plan_len)? }.to_vec()); let opts = unsafe { input(opt_ptr, opt_len)? }; let options = parse_options(opts, Side::Open)?; ops::validate::record_tree(&record, &plan, options.context.as_ref())?; @@ -520,8 +520,8 @@ pub unsafe extern "C" fn se_plan_check(plan_ptr: *const u8, plan_len: u32) -> u6 export(|| { // SAFETY: a host-owned range the export was handed; the borrow ends // before it returns. - let plan = unsafe { input(plan_ptr, plan_len)? }; - ops::plan_check(plan).map(|()| Vec::new()) + let plan = Bytes::new(unsafe { input(plan_ptr, plan_len)? }.to_vec()); + ops::plan_check(&plan).map(|()| Vec::new()) }) } @@ -557,7 +557,7 @@ pub unsafe extern "C" fn se_query_term( let value = unsafe { take_plaintext(val_ptr, val_len)? }; // SAFETY: host-owned ranges the export was handed; the borrows end // before it returns and before any wipe of an overlapping range. - let plan = unsafe { input(plan_ptr, plan_len)? }.to_vec(); + let plan = Bytes::new(unsafe { input(plan_ptr, plan_len)? }.to_vec()); let field = unsafe { input(field_ptr, field_len)? }.to_vec(); let operator = unsafe { input(op_ptr, op_len)? }.to_vec(); let opts = unsafe { input(opt_ptr, opt_len)? }; @@ -599,10 +599,10 @@ pub unsafe extern "C" fn se_json_open( export(|| { // SAFETY: host-owned ranges the export was handed; the borrows end // before it returns. - let rows = unsafe { input(rows_ptr, rows_len)? }.to_vec(); - let plan = unsafe { input(plan_ptr, plan_len)? }.to_vec(); + let rows = Bytes::new(unsafe { input(rows_ptr, rows_len)? }.to_vec()); + let plan = Bytes::new(unsafe { input(plan_ptr, plan_len)? }.to_vec()); let field = unsafe { input(field_ptr, field_len)? }.to_vec(); - let request = unsafe { input(req_ptr, req_len)? }.to_vec(); + let request = Bytes::new(unsafe { input(req_ptr, req_len)? }.to_vec()); let opts = unsafe { input(opt_ptr, opt_len)? }; ops::validate::json_open(&rows, &plan, &field, &request)?; let options = parse_options(opts, Side::Mint)?; @@ -647,10 +647,10 @@ pub unsafe extern "C" fn se_verify( let (query, values) = (query?, values?); // SAFETY: host-owned ranges the export was handed; the borrows end // before it returns. - let plan = unsafe { input(plan_ptr, plan_len)? }; + let plan = Bytes::new(unsafe { input(plan_ptr, plan_len)? }.to_vec()); let field = unsafe { input(field_ptr, field_len)? }; let operator = unsafe { input(op_ptr, op_len)? }; - ops::verify(query.as_slice(), values.as_slice(), plan, field, operator) + ops::verify(&query, &values, &plan, field, operator) }) } @@ -682,11 +682,11 @@ pub unsafe extern "C" fn se_target_limit( // SAFETY: host-owned ranges the export was handed; the borrows end // before it returns. let term = unsafe { input(term_ptr, term_len)? }; - let stats = unsafe { input(stats_ptr, stats_len)? }; - let plan = unsafe { input(plan_ptr, plan_len)? }; + let stats = Bytes::new(unsafe { input(stats_ptr, stats_len)? }.to_vec()); + let plan = Bytes::new(unsafe { input(plan_ptr, plan_len)? }.to_vec()); let field = unsafe { input(field_ptr, field_len)? }; let operator = unsafe { input(op_ptr, op_len)? }; - ops::target_limit(term, stats, plan, field, operator, want) + ops::target_limit(term, &stats, &plan, field, operator, want) }) } @@ -717,9 +717,9 @@ pub unsafe extern "C" fn se_operators( export(|| { // SAFETY: host-owned ranges the export was handed; the borrows end // before they return. - let plan = unsafe { input(plan_ptr, plan_len)? }; + let plan = Bytes::new(unsafe { input(plan_ptr, plan_len)? }.to_vec()); let field = unsafe { input(field_ptr, field_len)? }; - ops::operators(plan, field) + ops::operators(&plan, field) }) } @@ -753,7 +753,7 @@ pub extern "C" fn se_io() -> u64 { pub unsafe extern "C" fn se_resume(handle: u64, resp_ptr: *mut u8, resp_len: u32) -> u64 { export(|| { let bytes = unsafe { take_plaintext(resp_ptr, resp_len) }; - let responses = bytes.and_then(|bytes| io::decode_responses(&bytes)); + let responses = bytes.and_then(|bytes| io::decode_responses(bytes.risky_ref())); let responses = responses.inspect_err(|_| { let _ = step::abort(handle); })?; diff --git a/languages/golang/encrypt/guest/src/io.rs b/languages/golang/encrypt/guest/src/io.rs index 29206fd83..dad3a6e63 100644 --- a/languages/golang/encrypt/guest/src/io.rs +++ b/languages/golang/encrypt/guest/src/io.rs @@ -29,6 +29,7 @@ use serde::{Deserialize, Serialize, Serializer}; use stack_encrypt::dynamic::frame::serde::{from_slice, to_vec}; +use stack_encrypt::{Buffer, Controlled as _}; use stack_guest_abi::last_error::malformed; use stack_guest_abi::step::{Request, Response}; use zeroize::Zeroizing; @@ -63,14 +64,24 @@ pub fn encode_step(handle: u64, requests: &[Request]) -> Result, u32> { }) .collect(), }; - let frame = Zeroizing::new(to_vec(&wire).map_err(|_| STATUS_ENCODING)?); - // Sized exactly, as every output is: the registry would otherwise - // reallocate a buffer with spare capacity and leave the old one unwiped. + // A `Buffer`, which wipes on drop and as it grows. + let frame = to_vec(&wire).map_err(|_| STATUS_ENCODING)?; + to_host(&frame) + .ok_or_else(|| stack_guest_abi::last_error::internal("no memory for a step's requests")) +} + +/// A finished frame, copied into the output buffer the host reads. +/// +/// This is where a frame's bytes leave the guest, so this is the one place +/// the guest reads a `Buffer` through `risky_ref`. The `Buffer` is still +/// wiped when it drops. The copy is sized exactly, as every output is: the +/// registry would otherwise reallocate a buffer with spare capacity, and +/// leave the old one unwiped. `None` means the copy could not be allocated. +pub(crate) fn to_host(frame: &Buffer) -> Option> { let mut out = Vec::new(); - out.try_reserve_exact(frame.len()) - .map_err(|_| stack_guest_abi::last_error::internal("no memory for a step's requests"))?; - out.extend_from_slice(&frame); - Ok(out) + out.try_reserve_exact(frame.len()).ok()?; + out.extend_from_slice(frame.risky_ref()); + Some(out) } /// The responses the host handed `se_resume`, copied out of its buffer into diff --git a/languages/golang/encrypt/guest/src/ops.rs b/languages/golang/encrypt/guest/src/ops.rs index 3b2c65e25..4389d901c 100644 --- a/languages/golang/encrypt/guest/src/ops.rs +++ b/languages/golang/encrypt/guest/src/ops.rs @@ -50,9 +50,11 @@ use stack_encrypt::dynamic::{self, Scope, ValueFrame}; use stack_encrypt::sem::MatchOptions; use stack_encrypt::target::IndexSpec; use stack_encrypt::ErrorPayload; -use stack_encrypt::{CipherText, KeysetCipher, Label, Node, SealedValue, StackCipherText}; +use stack_encrypt::{ + AsProtectedRef, CipherText, Controlled, KeysetCipher, Label, Node, Protected, ProtectedRef, + SealedValue, StackCipherText, +}; use stack_kms::{DataKeySource, IndexKeySource}; -use zeroize::Zeroizing; use stack_guest_abi::last_error; @@ -73,6 +75,12 @@ pub const TERM_OPE: u32 = 4; /// encoding — the shape that crosses the FFI codec. type BytesTree = Node>; +/// An input frame the host handed over: a plan, a context, statistics, or +/// plaintext. The export takes it into a guest buffer, and this wipes it +/// when it drops. Plaintext moves in from the host's buffer, which +/// [`take_plaintext`](stack_guest_abi::abi::take_plaintext) wipes at once. +pub type Bytes = Protected>; + // ============================================================================= // Terms // ============================================================================= @@ -96,8 +104,8 @@ type BytesTree = Node>; /// extended context. pub async fn term( cipher: &KeysetCipher<'_, K>, - value: &[u8], - context: &[u8], + value: &Bytes, + context: &Bytes, kind: u32, ) -> Result, u32> where @@ -117,10 +125,10 @@ where /// are not a frame are refused as every other input's are, before the /// context's own grammar. fn parse_context( - context: &[u8], + context: &Bytes, ) -> Result>, u32> { let _ = parse_frame(context)?; - dynamic::context(context).map_err(|e| fail_dynamic(&e)) + dynamic::context(lend(context)).map_err(|e| fail_dynamic(&e)) } /// The static half of a term: the kind is one of the ABI's table, and the @@ -174,8 +182,8 @@ fn parse_term(value: Frame<'_>, kind: u32) -> Result { /// [`dynamic::record`]'s to state. pub async fn encrypt_record( cipher: &KeysetCipher<'_, K>, - source: &[u8], - plan: &[u8], + source: &Bytes, + plan: &Bytes, ) -> Result, u32> where K: DataKeySource + IndexKeySource + Sync + 'static, @@ -209,7 +217,7 @@ where pub async fn decrypt_record( scope: Scope<'_, K>, record: &[u8], - plan: &[u8], + plan: &Bytes, expected: Option