vercel / edge-runtime

Developing, testing, and defining the runtime Web APIs for Edge infrastructure.
https://edge-runtime.vercel.app
MIT License
792 stars 76 forks source link

crypto.subtle.importKey does not accept ArrayBuffer (ArrayBuffer.prototype mismatch) #813

Open tksst opened 6 months ago

tksst commented 6 months ago

Node.js 20.11.1 edge-runtime@2.5.9

Bug Report

Current behavior

foo.js:

(async () => {
    const key = new ArrayBuffer(8);
    const data = new ArrayBuffer(8);

    const importedKey = await crypto.subtle.importKey(
        "raw",
        key,
        {
            name: "HMAC",
            hash: { name: "SHA-256" },
        },
        false,
        ["sign"],
    );

    await crypto.subtle.sign("HMAC", importedKey, data);
})();

cmd:

$ npm exec edge-runtime foo.js

result(error):

node:internal/crypto/webidl:45
  const err = new TypeError(message);
              ^

TypeError: Failed to execute 'importKey' on 'SubtleCrypto': 2nd argument is not instance of ArrayBuffer, Buffer, TypedArray, or DataView.
    at codedTypeError (node:internal/crypto/webidl:45:15)
    at makeException (node:internal/crypto/webidl:54:10)
    at converters.BufferSource (node:internal/crypto/webidl:221:11)
    at SubtleCrypto.importKey (node:internal/crypto/webcrypto:589:36)
    at evalmachine.<anonymous>:6:45
    at evalmachine.<anonymous>:19:3
    at Script.runInContext (node:vm:133:12)
    at runInContext (node:vm:287:6)
    at EdgeVM.evaluate (/dev/edge/node_modules/@edge-runtime/vm/dist/vm.js:26:38)
    at new EdgeVM (/dev/edge/node_modules/@edge-runtime/vm/dist/edge-vm.js:49:18) {
  code: 'ERR_INVALID_ARG_TYPE'
}

Node.js v20.11.1

Expected behavior/code

Done without error

Additional context/screenshots

The above code has been verified to work with raw Node.js, Firefox and Chrome.

ArrayBuffer.prototype seems to be different from the original. Node.js checks here: https://github.com/nodejs/node/blob/9b1bf44ea9e7785e38c93b7d22d32dbca262df6c/lib/internal/crypto/webidl.js#L183

return ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, V);

Wrapping with uint8array is a workaround:

(async () => {
    const key = new ArrayBuffer(8);
    const data = new ArrayBuffer(8);

    const importedKey = await crypto.subtle.importKey(
        "raw",
        new Uint8Array(key),
        {
            name: "HMAC",
            hash: { name: "SHA-256" },
        },
        false,
        ["sign"],
    );

    await crypto.subtle.sign("HMAC", importedKey, new Uint8Array(data));
})();
glenntws commented 5 months ago

Occuring the same issue while using gr2m/universal-github-app-jwt. They obviously generate an ArrayBuffer, but importKey fails with the exact same type error.

I can also replicate it simply by doing await crypto.suble.importKey("pkcs8", new ArrayBuffer(), .....).

god-benten commented 3 months ago

I wrote a simple test code.

new ArrayBuffer().constructor === ArrayBuffer

above code evaluated as false on edge-runtime though i'm not sure why...

Moe03 commented 2 months ago

any update on this? seems to not give the same error on cloudflare workers

Noitidart commented 1 week ago

Same situation here in my local development. I have not yet pushed this up to Vercel to test in production.

Using next 14.0.4 and node 18.18.2. (also tried with node 20.16.0)