oven-sh / bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
https://bun.sh
Other
73.71k stars 2.72k forks source link

CryptoKey objects cannot be cloned #9657

Open mbouaziz opened 6 months ago

mbouaziz commented 6 months ago

What version of Bun is running?

1.0.35+940448d6b

What platform is your computer?

Linux 6.1.0-1029-oem x86_64 x86_64

What steps can reproduce the bug?

$ bun init

In index.ts:

const algo = { name: "HMAC", hash: "SHA-256" };
const key = await crypto.subtle.generateKey(algo, false, ["sign"]);
const cloned_key = structuredClone(key);
$ bun ./index.ts

What is the expected behavior?

No errors, as with node

What do you see instead?

DataCloneError: The object can not be cloned.

Additional information

This is blocking passing keys to workers.

CryptoKey objects can be stored using the structured clone algorithm

according to https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto

Similar issue with Deno: https://github.com/denoland/deno/issues/12734

mbouaziz commented 6 months ago

I tried to debug it myself and stumbled upon this part of the code in ScriptExecutionContext.h:

    // These two methods are used when CryptoKeys are serialized into IndexedDB. As a side effect, it is also
    // used for things that utilize the same structure clone algorithm, for example, message passing between
    // worker and document.

    // For now these will return false. In the future, we will want to implement these similar to how WorkerGlobalScope.cpp does.
    // virtual bool wrapCryptoKey(const Vector<uint8_t>& key, Vector<uint8_t>& wrappedKey) = 0;
    // virtual bool unwrapCryptoKey(const Vector<uint8_t>& wrappedKey, Vector<uint8_t>& key) = 0;
    bool wrapCryptoKey(const Vector<uint8_t>& key, Vector<uint8_t>& wrappedKey) { return false; }

which was added in #3637 by @dylan-conway and reviewed by @Jarred-Sumner.

The serialization code looks implemented, in dumpIfTerminal for JSCryptoKey but it calls wrapCryptoKey which always return false and cancels the serialization.

I suspect the goal is to prevent people disclosing keys they wouldn't want to and the code snippet I gave should indeed be rejected. Though my real use case is to pass the key to a worker with postMessage, which seems legit.

mbouaziz commented 6 months ago

Actually I have misunderstood wrapCryptoKey: it is not disallowing serializing the key, the key wrapping for serialization is just not implemented and it makes the whole serialization fail.