Skip to content

Commit

Permalink
Assorted WebCrypto API fixes
Browse files Browse the repository at this point in the history
- Accept `Ed25519` algorithm (supported as of cloudflare/workerd#500)
- Return `Ed25519` as the algorithm for `NODE-ED25519` keys
- Mark `X448` and `Ed448` algorithms as unsupported

This passes Miniflare's test suite on Node 16.13.0 and 20.1.0.

It also passes `panva/jose`'s `workerd` tap tests on Node 16.17.0 and
20.1.0. Some of those tests fail on 16.13.0 as support for the
`X25519` algorithm was only added in 16.17.0. See
https://nodejs.org/api/webcrypto.html#web-crypto-api for details.
  • Loading branch information
mrbbot committed May 4, 2023
1 parent b5c58ef commit 539b33c
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 8 deletions.
24 changes: 19 additions & 5 deletions packages/core/src/standards/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,20 @@ const usesModernEd25519 = (async () => {
async function ensureValidNodeAlgorithm(
algorithm: webcrypto.AlgorithmIdentifier | webcrypto.EcKeyAlgorithm
): Promise<webcrypto.AlgorithmIdentifier | webcrypto.EcKeyAlgorithm> {
// "X448" and "Ed448" are not supported by Workers
if (
typeof algorithm === "object" &&
(algorithm.name === "X448" || algorithm.name === "Ed448")
) {
throw new DOMException("Unrecognized name.", "NotSupportedError");
}
if (
typeof algorithm === "object" &&
algorithm.name === "Ed25519" &&
!(await usesModernEd25519)
) {
return { name: "NODE-ED25519", namedCurve: "NODE-ED25519" };
}
if (
typeof algorithm === "object" &&
algorithm.name === "NODE-ED25519" &&
Expand All @@ -83,19 +97,19 @@ async function ensureValidNodeAlgorithm(
}

function ensureValidWorkerKey(key: webcrypto.CryptoKey): webcrypto.CryptoKey {
// Users' workers will expect to see the `NODE-ED25519` algorithm, even if
// we're using "Ed25519" internally (https://github.com/panva/jose/issues/446)
if (key.algorithm.name === "Ed25519") key.algorithm.name = "NODE-ED25519";
// Users' workers will expect to see the `Ed25519` algorithm, even if we're
// using on an old Node version and using "Ed25519" internally
if (key.algorithm.name === "NODE-ED25519") key.algorithm.name = "Ed25519";
return key;
}

async function ensureValidNodeKey(
key: webcrypto.CryptoKey
): Promise<webcrypto.CryptoKey> {
if (key.algorithm.name === "NODE-ED25519" && (await usesModernEd25519)) {
if (key.algorithm.name === "Ed25519" && !(await usesModernEd25519)) {
return new Proxy(key, {
get(target, property, receiver) {
if (property === "algorithm") return { name: "Ed25519" };
if (property === "algorithm") return { name: "NODE-ED25519" };
return Reflect.get(target, property, receiver);
},
});
Expand Down
6 changes: 3 additions & 3 deletions packages/core/test/standards/crypto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ test("crypto: generateKey/exportKey: supports NODE-ED25519 algorithm", async (t)
true,
["sign", "verify"]
);
t.is(keyPair.publicKey.algorithm.name, "NODE-ED25519");
t.is(keyPair.privateKey.algorithm.name, "NODE-ED25519");
t.is(keyPair.publicKey.algorithm.name, "Ed25519");
t.is(keyPair.privateKey.algorithm.name, "Ed25519");
const exported = await crypto.subtle.exportKey("raw", keyPair.publicKey);
t.is(exported.byteLength, 32);
});
Expand All @@ -126,7 +126,7 @@ test("crypto: importKey/exportKey: supports NODE-ED25519 public keys", async (t)
true,
["verify"]
);
t.is(publicKey.algorithm.name, "NODE-ED25519");
t.is(publicKey.algorithm.name, "Ed25519");
const exported = await crypto.subtle.exportKey("raw", publicKey);
t.is(Buffer.from(exported).toString("hex"), keyData);
});
Expand Down

0 comments on commit 539b33c

Please sign in to comment.