Revert "Fix RSA JWK import validation bug causing Jose library failures" (#22307)

Test did not fail in previous build of Bun

Reverts oven-sh/bun#22264
This commit is contained in:
Jarred Sumner
2025-09-01 02:45:01 -07:00
committed by GitHub
parent 0b98086c3d
commit d957a81c0a
6 changed files with 31 additions and 127 deletions

View File

@@ -1,6 +1,11 @@
{
"private": true,
"name": "bun",
"version": "1.2.22",
"workspaces": [
"./packages/bun-types",
"./packages/@types/bun"
],
"devDependencies": {
"@lezer/common": "^1.2.3",
"@lezer/cpp": "^1.1.3",
@@ -16,7 +21,6 @@
"source-map-js": "^1.2.0",
"typescript": "5.9.2"
},
"private": true,
"resolutions": {
"bun-types": "workspace:packages/bun-types",
"@types/bun": "workspace:packages/@types/bun"
@@ -81,9 +85,5 @@
"node:test:cp": "bun ./scripts/fetch-node-test.ts ",
"clean:zig": "rm -rf build/debug/cache/zig build/debug/CMakeCache.txt 'build/debug/*.o' .zig-cache zig-out || true",
"sync-webkit-source": "bun ./scripts/sync-webkit-source.ts"
},
"workspaces": [
"./packages/bun-types",
"./packages/@types/bun"
]
}
}

View File

@@ -66,7 +66,7 @@ RefPtr<CryptoKeyRSA> CryptoKeyRSA::importJwk(CryptoAlgorithmIdentifier algorithm
auto privateExponent = base64URLDecode(keyData.d);
if (!privateExponent)
return nullptr;
if (keyData.p.isNull() && keyData.q.isNull() && keyData.dp.isNull() && keyData.dq.isNull() && keyData.qi.isNull()) {
if (keyData.p.isNull() && keyData.q.isNull() && keyData.dp.isNull() && keyData.dp.isNull() && keyData.qi.isNull()) {
auto privateKeyComponents = CryptoKeyRSAComponents::createPrivate(WTFMove(*modulus), WTFMove(*exponent), WTFMove(*privateExponent));
// Notice: CryptoAlgorithmIdentifier::SHA_1 is just a placeholder. It should not have any effect if hash is std::nullopt.
return CryptoKeyRSA::create(algorithm, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, *privateKeyComponents, extractable, usages);

View File

@@ -125,10 +125,10 @@ static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAl
auto identifier = CryptoAlgorithmRegistry::singleton().identifier(params.name);
if (!identifier) [[unlikely]]
RELEASE_AND_RETURN(scope, Exception { NotSupportedError });
return Exception { NotSupportedError };
if (*identifier == CryptoAlgorithmIdentifier::Ed25519 && !isSafeCurvesEnabled(state))
RELEASE_AND_RETURN(scope, Exception { NotSupportedError });
return Exception { NotSupportedError };
std::unique_ptr<CryptoAlgorithmParameters> result;
switch (operation) {
@@ -137,7 +137,7 @@ static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAl
switch (*identifier) {
case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
if (isRSAESPKCSWebCryptoDeprecated(state))
RELEASE_AND_RETURN(scope, (Exception { NotSupportedError, "RSAES-PKCS1-v1_5 support is deprecated"_s }));
return Exception { NotSupportedError, "RSAES-PKCS1-v1_5 support is deprecated"_s };
result = makeUnique<CryptoAlgorithmParameters>(params);
break;
case CryptoAlgorithmIdentifier::RSA_OAEP: {
@@ -166,7 +166,7 @@ static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAl
break;
}
default:
RELEASE_AND_RETURN(scope, Exception { NotSupportedError });
return Exception { NotSupportedError };
}
break;
case Operations::Sign:
@@ -182,7 +182,7 @@ static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAl
RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
auto hashIdentifier = toHashIdentifier(state, params.hash);
RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
if (hashIdentifier.hasException()) RELEASE_AND_RETURN(scope, hashIdentifier.releaseException());
if (hashIdentifier.hasException()) return hashIdentifier.releaseException();
params.hashIdentifier = hashIdentifier.releaseReturnValue();
result = makeUnique<CryptoAlgorithmEcdsaParams>(params);
break;
@@ -194,7 +194,7 @@ static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAl
break;
}
default:
RELEASE_AND_RETURN(scope, Exception { NotSupportedError });
return Exception { NotSupportedError };
}
break;
case Operations::Digest:
@@ -207,14 +207,14 @@ static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAl
result = makeUnique<CryptoAlgorithmParameters>(params);
break;
default:
RELEASE_AND_RETURN(scope, Exception { NotSupportedError });
return Exception { NotSupportedError };
}
break;
case Operations::GenerateKey:
switch (*identifier) {
case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: {
if (isRSAESPKCSWebCryptoDeprecated(state))
RELEASE_AND_RETURN(scope, (Exception { NotSupportedError, "RSAES-PKCS1-v1_5 support is deprecated"_s }));
return Exception { NotSupportedError, "RSAES-PKCS1-v1_5 support is deprecated"_s };
auto params = convertDictionary<CryptoAlgorithmRsaKeyGenParams>(state, value.get());
RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
result = makeUnique<CryptoAlgorithmRsaKeyGenParams>(params);
@@ -227,7 +227,7 @@ static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAl
RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
auto hashIdentifier = toHashIdentifier(state, params.hash);
RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
if (hashIdentifier.hasException()) RELEASE_AND_RETURN(scope, hashIdentifier.releaseException());
if (hashIdentifier.hasException()) return hashIdentifier.releaseException();
params.hashIdentifier = hashIdentifier.releaseReturnValue();
result = makeUnique<CryptoAlgorithmRsaHashedKeyGenParams>(params);
break;
@@ -247,7 +247,7 @@ static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAl
RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
auto hashIdentifier = toHashIdentifier(state, params.hash);
RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
if (hashIdentifier.hasException()) RELEASE_AND_RETURN(scope, hashIdentifier.releaseException());
if (hashIdentifier.hasException()) return hashIdentifier.releaseException();
params.hashIdentifier = hashIdentifier.releaseReturnValue();
result = makeUnique<CryptoAlgorithmHmacKeyParams>(params);
break;
@@ -266,7 +266,7 @@ static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAl
result = makeUnique<CryptoAlgorithmParameters>(params);
break;
default:
RELEASE_AND_RETURN(scope, Exception { NotSupportedError });
return Exception { NotSupportedError };
}
break;
case Operations::DeriveBits:
@@ -302,7 +302,7 @@ static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAl
RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
auto hashIdentifier = toHashIdentifier(state, params.hash);
RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
if (hashIdentifier.hasException()) RELEASE_AND_RETURN(scope, hashIdentifier.releaseException());
if (hashIdentifier.hasException()) return hashIdentifier.releaseException();
params.hashIdentifier = hashIdentifier.releaseReturnValue();
result = makeUnique<CryptoAlgorithmHkdfParams>(params);
break;
@@ -312,20 +312,20 @@ static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAl
RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
auto hashIdentifier = toHashIdentifier(state, params.hash);
RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
if (hashIdentifier.hasException()) RELEASE_AND_RETURN(scope, hashIdentifier.releaseException());
if (hashIdentifier.hasException()) return hashIdentifier.releaseException();
params.hashIdentifier = hashIdentifier.releaseReturnValue();
result = makeUnique<CryptoAlgorithmPbkdf2Params>(params);
break;
}
default:
RELEASE_AND_RETURN(scope, Exception { NotSupportedError });
return Exception { NotSupportedError };
}
break;
case Operations::ImportKey:
switch (*identifier) {
case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
if (isRSAESPKCSWebCryptoDeprecated(state))
RELEASE_AND_RETURN(scope, (Exception { NotSupportedError, "RSAES-PKCS1-v1_5 support is deprecated"_s }));
return Exception { NotSupportedError, "RSAES-PKCS1-v1_5 support is deprecated"_s };
result = makeUnique<CryptoAlgorithmParameters>(params);
break;
case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
@@ -335,7 +335,7 @@ static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAl
RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
auto hashIdentifier = toHashIdentifier(state, params.hash);
RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
if (hashIdentifier.hasException()) RELEASE_AND_RETURN(scope, hashIdentifier.releaseException());
if (hashIdentifier.hasException()) return hashIdentifier.releaseException();
params.hashIdentifier = hashIdentifier.releaseReturnValue();
result = makeUnique<CryptoAlgorithmRsaHashedImportParams>(params);
break;
@@ -354,7 +354,7 @@ static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAl
RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
auto hashIdentifier = toHashIdentifier(state, params.hash);
RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
if (hashIdentifier.hasException()) RELEASE_AND_RETURN(scope, hashIdentifier.releaseException());
if (hashIdentifier.hasException()) return hashIdentifier.releaseException();
params.hashIdentifier = hashIdentifier.releaseReturnValue();
result = makeUnique<CryptoAlgorithmHmacKeyParams>(params);
break;
@@ -375,9 +375,9 @@ static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAl
case CryptoAlgorithmIdentifier::SHA_256:
case CryptoAlgorithmIdentifier::SHA_384:
case CryptoAlgorithmIdentifier::SHA_512:
RELEASE_AND_RETURN(scope, Exception { NotSupportedError });
return Exception { NotSupportedError };
case CryptoAlgorithmIdentifier::None:
RELEASE_AND_RETURN(scope, Exception { NotSupportedError });
return Exception { NotSupportedError };
}
break;
@@ -388,7 +388,7 @@ static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAl
result = makeUnique<CryptoAlgorithmParameters>(params);
break;
default:
RELEASE_AND_RETURN(scope, Exception { NotSupportedError });
return Exception { NotSupportedError };
}
break;
case Operations::GetKeyLength:
@@ -408,7 +408,7 @@ static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAl
RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
auto hashIdentifier = toHashIdentifier(state, params.hash);
RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
if (hashIdentifier.hasException()) RELEASE_AND_RETURN(scope, hashIdentifier.releaseException());
if (hashIdentifier.hasException()) return hashIdentifier.releaseException();
params.hashIdentifier = hashIdentifier.releaseReturnValue();
result = makeUnique<CryptoAlgorithmHmacKeyParams>(params);
break;
@@ -418,13 +418,13 @@ static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAl
result = makeUnique<CryptoAlgorithmParameters>(params);
break;
default:
RELEASE_AND_RETURN(scope, Exception { NotSupportedError });
return Exception { NotSupportedError };
}
break;
}
result->identifier = *identifier;
RELEASE_AND_RETURN(scope, result);
return result;
}
static CryptoKeyUsageBitmap toCryptoKeyUsageBitmap(CryptoKeyUsage usage)
@@ -801,9 +801,7 @@ void SubtleCrypto::generateKey(JSC::JSGlobalObject& state, AlgorithmIdentifier&&
auto scope = DECLARE_THROW_SCOPE(vm);
auto paramsOrException = normalizeCryptoAlgorithmParameters(state, WTFMove(algorithmIdentifier), Operations::GenerateKey);
if (paramsOrException.hasException()) {
auto exception = paramsOrException.releaseException();
scope.release();
promise->reject(exception);
promise->reject(paramsOrException.releaseException());
return;
}
auto params = paramsOrException.releaseReturnValue();

View File

@@ -52,7 +52,6 @@
"isbot": "5.1.13",
"jest-extended": "4.0.0",
"jimp": "1.6.0",
"jose": "5.10.0",
"jsdom": "25.0.1",
"jsonwebtoken": "9.0.2",
"jws": "4.0.0",
@@ -1623,8 +1622,6 @@
"jimp": ["jimp@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/diff": "1.6.0", "@jimp/js-bmp": "1.6.0", "@jimp/js-gif": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/js-tiff": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/plugin-blur": "1.6.0", "@jimp/plugin-circle": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-contain": "1.6.0", "@jimp/plugin-cover": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-displace": "1.6.0", "@jimp/plugin-dither": "1.6.0", "@jimp/plugin-fisheye": "1.6.0", "@jimp/plugin-flip": "1.6.0", "@jimp/plugin-hash": "1.6.0", "@jimp/plugin-mask": "1.6.0", "@jimp/plugin-print": "1.6.0", "@jimp/plugin-quantize": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/plugin-rotate": "1.6.0", "@jimp/plugin-threshold": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0" } }, "sha512-YcwCHw1kiqEeI5xRpDlPPBGL2EOpBKLwO4yIBJcXWHPj5PnA5urGq0jbyhM5KoNpypQ6VboSoxc9D8HyfvngSg=="],
"jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="],
"joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="],
"jpeg-js": ["jpeg-js@0.4.4", "", {}, "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg=="],

View File

@@ -57,7 +57,6 @@
"isbot": "5.1.13",
"jest-extended": "4.0.0",
"jimp": "1.6.0",
"jose": "5.10.0",
"jsdom": "25.0.1",
"jsonwebtoken": "9.0.2",
"jws": "4.0.0",

View File

@@ -1,90 +0,0 @@
import { beforeAll, expect, test } from "bun:test";
import { importJWK } from "jose";
let fullPrivateJWK: JsonWebKey;
let publicJWK: JsonWebKey;
let minimalPrivateJWK: JsonWebKey;
beforeAll(async () => {
const keyPair = await crypto.subtle.generateKey(
{ name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]), hash: "SHA-256" },
true,
["sign", "verify"],
);
fullPrivateJWK = await crypto.subtle.exportKey("jwk", keyPair.privateKey);
publicJWK = await crypto.subtle.exportKey("jwk", keyPair.publicKey);
minimalPrivateJWK = {
kty: fullPrivateJWK.kty,
n: fullPrivateJWK.n,
e: fullPrivateJWK.e,
d: fullPrivateJWK.d,
} as JsonWebKey;
});
test("RSA JWK import should work with valid private key", async () => {
const importedKey = await crypto.subtle.importKey(
"jwk",
fullPrivateJWK,
{
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
},
false,
["sign"],
);
expect(importedKey.type).toBe("private");
expect(importedKey.algorithm.name).toBe("RSASSA-PKCS1-v1_5");
expect(importedKey.algorithm.hash.name).toBe("SHA-256");
expect(importedKey.usages).toEqual(["sign"]);
expect(importedKey.extractable).toBe(false);
});
test("RSA JWK import should work with public key", async () => {
const importedKey = await crypto.subtle.importKey(
"jwk",
publicJWK,
{
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
},
false,
["verify"],
);
expect(importedKey.type).toBe("public");
expect(importedKey.algorithm.name).toBe("RSASSA-PKCS1-v1_5");
expect(importedKey.usages).toEqual(["verify"]);
});
test("RSA JWK import should reject minimal private key (no CRT params)", async () => {
// Note: WebCrypto spec requires CRT parameters for RSA private keys
// This test verifies that minimal private keys without CRT parameters are properly rejected
await expect(
crypto.subtle.importKey(
"jwk",
minimalPrivateJWK,
{
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
},
false,
["sign"],
),
).rejects.toThrow();
});
test("RSA JWK import should reject partial CRT params", async () => {
const partial = { ...fullPrivateJWK };
// @ts-expect-error deleting for test
delete (partial as any).dq;
await expect(
crypto.subtle.importKey("jwk", partial, { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, false, ["sign"]),
).rejects.toThrow();
});
test("Jose library should work with RSA JWK import after fix", async () => {
// This should not throw a DataError after the fix
const importedKey = await importJWK(fullPrivateJWK, "RS256");
expect(importedKey).toBeDefined();
});