This commit is contained in:
Jarred Sumner
2025-01-26 02:21:40 -08:00
committed by GitHub
parent 75a95aa5fa
commit 89eea169c0
5 changed files with 62 additions and 43 deletions

View File

@@ -20,13 +20,14 @@ using namespace JSC;
init.set(jsOwnedString(init.vm, name.string())); \
});
#define BUN_COMMON_STRINGS_LAZY_PROPERTY_DEFINITION_NOT_BUILTIN_NAMES(jsName) \
this->m_commonString_##jsName.initLater( \
[](const JSC::LazyProperty<JSGlobalObject, JSString>::Initializer& init) { \
init.set(jsOwnedString(init.vm, #jsName##_s)); \
#define BUN_COMMON_STRINGS_LAZY_PROPERTY_DEFINITION_NOT_BUILTIN_NAMES(methodName, stringLiteral) \
this->m_commonString_##methodName.initLater( \
[](const JSC::LazyProperty<JSGlobalObject, JSString>::Initializer& init) { \
init.set(jsOwnedString(init.vm, stringLiteral##_s)); \
});
#define BUN_COMMON_STRINGS_LAZY_PROPERTY_VISITOR(name) this->m_commonString_##name.visit(visitor);
#define BUN_COMMON_STRINGS_LAZY_PROPERTY_VISITOR_NOT_BUILTIN_NAMES(name, literal) this->m_commonString_##name.visit(visitor);
void CommonStrings::initialize()
{
@@ -38,7 +39,7 @@ template<typename Visitor>
void CommonStrings::visit(Visitor& visitor)
{
BUN_COMMON_STRINGS_EACH_NAME(BUN_COMMON_STRINGS_LAZY_PROPERTY_VISITOR)
BUN_COMMON_STRINGS_EACH_NAME_NOT_BUILTIN_NAMES(BUN_COMMON_STRINGS_LAZY_PROPERTY_VISITOR)
BUN_COMMON_STRINGS_EACH_NAME_NOT_BUILTIN_NAMES(BUN_COMMON_STRINGS_LAZY_PROPERTY_VISITOR_NOT_BUILTIN_NAMES)
}
template void CommonStrings::visit(JSC::AbstractSlotVisitor&);

View File

@@ -11,17 +11,23 @@
// These ones don't need to be in BunBuiltinNames.h
// If we don't use it as an identifier name, but we want to avoid allocating the string frequently, put it in this list.
#define BUN_COMMON_STRINGS_EACH_NAME_NOT_BUILTIN_NAMES(macro) \
macro(SystemError) \
macro(S3Error) \
macro(utf8) \
macro(ucs2) \
macro(utf16le) \
macro(latin1) \
macro(ascii) \
macro(base64) \
macro(base64url) \
macro(hex) \
macro(buffer)
macro(systemError, "SystemError") \
macro(s3Error, "S3Error") \
macro(utf8, "utf8") \
macro(ucs2, "ucs2") \
macro(utf16le, "utf16le") \
macro(latin1, "latin1") \
macro(ascii, "ascii") \
macro(base64, "base64") \
macro(base64url, "base64url") \
macro(hex, "hex") \
macro(buffer, "buffer") \
macro(rsa, "rsa") \
macro(rsaPss, "rsa-pss") \
macro(ec, "ec") \
macro(x25519, "x25519") \
macro(ed25519, "ed25519")
// clang-format on
#define BUN_COMMON_STRINGS_ACCESSOR_DEFINITION(name) \
@@ -30,15 +36,21 @@
return m_commonString_##name.getInitializedOnMainThread(globalObject); \
}
#define BUN_COMMON_STRINGS_ACCESSOR_DEFINITION_NOT_BUILTIN_NAMES(name, literal) \
BUN_COMMON_STRINGS_ACCESSOR_DEFINITION(name)
#define BUN_COMMON_STRINGS_LAZY_PROPERTY_DECLARATION(name) \
JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSString> m_commonString_##name;
#define BUN_COMMON_STRINGS_LAZY_PROPERTY_DECLARATION_NOT_BUILTIN_NAMES(name, literal) \
BUN_COMMON_STRINGS_LAZY_PROPERTY_DECLARATION(name)
namespace Bun {
class CommonStrings {
public:
BUN_COMMON_STRINGS_EACH_NAME(BUN_COMMON_STRINGS_ACCESSOR_DEFINITION)
BUN_COMMON_STRINGS_EACH_NAME_NOT_BUILTIN_NAMES(BUN_COMMON_STRINGS_ACCESSOR_DEFINITION)
BUN_COMMON_STRINGS_EACH_NAME_NOT_BUILTIN_NAMES(BUN_COMMON_STRINGS_ACCESSOR_DEFINITION_NOT_BUILTIN_NAMES)
void initialize();
template<typename Visitor>
@@ -46,10 +58,12 @@ public:
private:
BUN_COMMON_STRINGS_EACH_NAME(BUN_COMMON_STRINGS_LAZY_PROPERTY_DECLARATION)
BUN_COMMON_STRINGS_EACH_NAME_NOT_BUILTIN_NAMES(BUN_COMMON_STRINGS_LAZY_PROPERTY_DECLARATION)
BUN_COMMON_STRINGS_EACH_NAME_NOT_BUILTIN_NAMES(BUN_COMMON_STRINGS_LAZY_PROPERTY_DECLARATION_NOT_BUILTIN_NAMES)
};
} // namespace Bun
#undef BUN_COMMON_STRINGS_ACCESSOR_DEFINITION
#undef BUN_COMMON_STRINGS_LAZY_PROPERTY_DECLARATION
#undef BUN_COMMON_STRINGS_ACCESSOR_DEFINITION_NOT_BUILTIN_NAMES
#undef BUN_COMMON_STRINGS_LAZY_PROPERTY_DECLARATION_NOT_BUILTIN_NAMES

View File

@@ -21,7 +21,9 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
#include "root.h"
#include "ErrorCode.h"
#include "BunCommonStrings.h"
#include "KeyObject.h"
#include "JavaScriptCore/JSArrayBufferView.h"
#include "JavaScriptCore/JSCJSValue.h"
@@ -611,9 +613,9 @@ JSC_DEFINE_HOST_FUNCTION(KeyObject__createPrivateKey, (JSC::JSGlobalObject * glo
auto impl = result.releaseNonNull();
return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl)));
} else if (pKeyID == EVP_PKEY_X25519) {
auto result = CryptoKeyOKP::importPkcs8(CryptoAlgorithmIdentifier::Ed25519, CryptoKeyOKP::NamedCurve::X25519, Vector<uint8_t>(std::span { (uint8_t*)data, byteLength }), true, CryptoKeyUsageSign);
auto result = CryptoKeyOKP::importPkcs8(CryptoAlgorithmIdentifier::X25519, CryptoKeyOKP::NamedCurve::X25519, Vector<uint8_t>(std::span { (uint8_t*)data, byteLength }), true, CryptoKeyUsageDeriveKey);
if (UNLIKELY(result == nullptr)) {
throwException(globalObject, scope, createTypeError(globalObject, "Invalid Ed25519 private key"_s));
throwException(globalObject, scope, createTypeError(globalObject, "Invalid X25519 private key"_s));
return {};
}
auto impl = result.releaseNonNull();
@@ -987,7 +989,7 @@ JSC_DEFINE_HOST_FUNCTION(KeyObject__createPublicKey, (JSC::JSGlobalObject * glob
}
return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl)));
} else if (jwk.crv == "X25519"_s) {
auto result = CryptoKeyOKP::importPublicJwk(CryptoAlgorithmIdentifier::Ed25519, CryptoKeyOKP::NamedCurve::X25519, WTFMove(jwk), true, CryptoKeyUsageVerify);
auto result = CryptoKeyOKP::importPublicJwk(CryptoAlgorithmIdentifier::X25519, CryptoKeyOKP::NamedCurve::X25519, WTFMove(jwk), true, CryptoKeyUsageDeriveKey);
if (UNLIKELY(result == nullptr)) {
throwException(globalObject, scope, createTypeError(globalObject, "Invalid X25519 public key"_s));
return {};
@@ -1076,12 +1078,12 @@ JSC_DEFINE_HOST_FUNCTION(KeyObject__createPublicKey, (JSC::JSGlobalObject * glob
auto impl = result.releaseNonNull();
return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl)));
} else if (pKeyID == EVP_PKEY_X25519) {
auto result = CryptoKeyOKP::importSpki(CryptoAlgorithmIdentifier::Ed25519, CryptoKeyOKP::NamedCurve::X25519, Vector<uint8_t>(std::span { (uint8_t*)pem.der_data, (size_t)pem.der_len }), true, CryptoKeyUsageVerify);
auto result = CryptoKeyOKP::importSpki(CryptoAlgorithmIdentifier::X25519, CryptoKeyOKP::NamedCurve::X25519, Vector<uint8_t>(std::span { (uint8_t*)pem.der_data, (size_t)pem.der_len }), true, CryptoKeyUsageDeriveKey);
if (pem.der_data) {
OPENSSL_clear_free(pem.der_data, pem.der_len);
}
if (UNLIKELY(result == nullptr)) {
throwException(globalObject, scope, createTypeError(globalObject, "Invalid Ed25519 public key"_s));
throwException(globalObject, scope, createTypeError(globalObject, "Invalid X25519 public key"_s));
return {};
}
auto impl = result.releaseNonNull();
@@ -1196,9 +1198,9 @@ JSC_DEFINE_HOST_FUNCTION(KeyObject__createPublicKey, (JSC::JSGlobalObject * glob
auto impl = result.releaseNonNull();
return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl)));
} else if (pKeyID == EVP_PKEY_X25519) {
auto result = CryptoKeyOKP::importSpki(CryptoAlgorithmIdentifier::Ed25519, CryptoKeyOKP::NamedCurve::X25519, Vector<uint8_t>(std::span { (uint8_t*)data, byteLength }), true, CryptoKeyUsageVerify);
auto result = CryptoKeyOKP::importSpki(CryptoAlgorithmIdentifier::X25519, CryptoKeyOKP::NamedCurve::X25519, Vector<uint8_t>(std::span { (uint8_t*)data, byteLength }), true, CryptoKeyUsageDeriveKey);
if (UNLIKELY(result == nullptr)) {
throwException(globalObject, scope, createTypeError(globalObject, "Invalid Ed25519 public key"_s));
throwException(globalObject, scope, createTypeError(globalObject, "Invalid X25519 public key"_s));
return {};
}
auto impl = result.releaseNonNull();
@@ -2502,11 +2504,15 @@ JSC_DEFINE_HOST_FUNCTION(KeyObject_AsymmetricKeyDetails, (JSC::JSGlobalObject *
obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "namedCurve"_s)), JSC::jsString(vm, named_curve), 0);
return JSC::JSValue::encode(obj);
}
case CryptoAlgorithmIdentifier::X25519:
case CryptoAlgorithmIdentifier::Ed25519: {
auto* obj = JSC::constructEmptyObject(lexicalGlobalObject, lexicalGlobalObject->objectPrototype(), 1);
auto& wrapped = key->wrapped();
const auto& okp = downcast<WebCore::CryptoKeyOKP>(wrapped);
obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "namedCurve"_s)), JSC::jsString(vm, okp.namedCurveString()), 0);
auto* globalObject = defaultGlobalObject(lexicalGlobalObject);
auto& commonStrings = globalObject->commonStrings();
JSString* namedCurveString = okp.namedCurve() == CryptoKeyOKP::NamedCurve::X25519 ? commonStrings.x25519String(lexicalGlobalObject) : commonStrings.ed25519String(lexicalGlobalObject);
obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "namedCurve"_s)), namedCurveString, 0);
return JSC::JSValue::encode(obj);
}
default:
@@ -2722,7 +2728,7 @@ JSC_DEFINE_HOST_FUNCTION(KeyObject__generateKeyPairSync, (JSC::JSGlobalObject *
obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "privateKey"_s)), JSCryptoKey::create(structure, zigGlobalObject, pair.privateKey.releaseNonNull()), 0);
return JSValue::encode(obj);
} else if (type_str == "x25519"_s) {
auto result = CryptoKeyOKP::generatePair(CryptoAlgorithmIdentifier::X25519, CryptoKeyOKP::NamedCurve::X25519, true, CryptoKeyUsageDeriveKey | CryptoKeyUsageDeriveBits);
auto result = CryptoKeyOKP::generatePair(CryptoAlgorithmIdentifier::X25519, CryptoKeyOKP::NamedCurve::X25519, true, CryptoKeyUsageDeriveKey | CryptoKeyUsageDeriveBits | CryptoKeyUsageSign | CryptoKeyUsageVerify);
if (result.hasException()) {
WebCore::propagateException(*lexicalGlobalObject, scope, result.releaseException());
return JSC::JSValue::encode(JSC::JSValue {});
@@ -2802,13 +2808,8 @@ JSC_DEFINE_HOST_FUNCTION(KeyObject__generateKeySync, (JSC::JSGlobalObject * lexi
JSC_DEFINE_HOST_FUNCTION(KeyObject__AsymmetricKeyType, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
{
ncrypto::ClearErrorOnReturn clearErrorOnReturn;
static const NeverDestroyed<String> values[] = {
MAKE_STATIC_STRING_IMPL("rsa"),
MAKE_STATIC_STRING_IMPL("rsa-pss"),
MAKE_STATIC_STRING_IMPL("ec"),
MAKE_STATIC_STRING_IMPL("x25519"),
MAKE_STATIC_STRING_IMPL("ed25519"),
};
auto* globalObject = defaultGlobalObject(lexicalGlobalObject);
auto& commonStrings = globalObject->commonStrings();
// TODO: Look into DSA and DH
if (auto* key = jsDynamicCast<JSCryptoKey*>(callFrame->argument(0))) {
@@ -2817,16 +2818,16 @@ JSC_DEFINE_HOST_FUNCTION(KeyObject__AsymmetricKeyType, (JSC::JSGlobalObject * le
case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
case CryptoAlgorithmIdentifier::RSA_OAEP:
return JSC::JSValue::encode(JSC::jsStringWithCache(lexicalGlobalObject->vm(), values[0]));
return JSC::JSValue::encode(commonStrings.rsaString(globalObject));
case CryptoAlgorithmIdentifier::RSA_PSS:
return JSC::JSValue::encode(JSC::jsStringWithCache(lexicalGlobalObject->vm(), values[1]));
return JSC::JSValue::encode(commonStrings.rsaPssString(globalObject));
case CryptoAlgorithmIdentifier::ECDSA:
case CryptoAlgorithmIdentifier::ECDH:
return JSC::JSValue::encode(JSC::jsStringWithCache(lexicalGlobalObject->vm(), values[2]));
case CryptoAlgorithmIdentifier::Ed25519: {
return JSC::JSValue::encode(commonStrings.ecString(globalObject));
case CryptoAlgorithmIdentifier::Ed25519:
case CryptoAlgorithmIdentifier::X25519: {
const auto& okpKey = downcast<WebCore::CryptoKeyOKP>(key->wrapped());
// TODO: CHECK THIS WHEN X488 AND ED448 ARE ADDED
return JSC::JSValue::encode(JSC::jsStringWithCache(lexicalGlobalObject->vm(), String(okpKey.namedCurve() == CryptoKeyOKP::NamedCurve::X25519 ? values[3] : values[4])));
return JSC::JSValue::encode(okpKey.namedCurve() == CryptoKeyOKP::NamedCurve::X25519 ? commonStrings.x25519String(globalObject) : commonStrings.ed25519String(globalObject));
}
default:
return JSC::JSValue::encode(JSC::jsUndefined());

View File

@@ -40,7 +40,7 @@ SYSV_ABI JSC::EncodedJSValue S3Error__toErrorInstance(const S3Error* arg0,
JSC::JSObject* result = JSC::ErrorInstance::create(globalObject, prototype, message, options);
result->putDirect(
vm, vm.propertyNames->name,
JSC::JSValue(defaultGlobalObject(globalObject)->commonStrings().S3ErrorString(globalObject)),
JSC::JSValue(defaultGlobalObject(globalObject)->commonStrings().s3ErrorString(globalObject)),
JSC::PropertyAttribute::DontEnum | 0);
if (err.code.tag != BunStringTag::Empty) {
JSC::JSValue code = Bun::toJS(globalObject, err.code);

View File

@@ -1664,10 +1664,13 @@ test("Ed25519 should work", async () => {
expect(publicKey.type).toBe("public");
expect(publicKey.asymmetricKeyType).toBe("ed25519");
expect(publicKey.asymmetricKeyDetails).toEqual({ namedCurve: "Ed25519" });
expect(privateKey.type).toBe("private");
expect(privateKey.asymmetricKeyType).toBe("ed25519");
expect(privateKey.asymmetricKeyDetails).toEqual({ namedCurve: "Ed25519" });
// TODO: this should be an empty object. Node doesn't always include the details.
expect(privateKey.asymmetricKeyDetails).toBeObject();
expect(publicKey.asymmetricKeyDetails).toBeObject();
{
const signature = sign(undefined, Buffer.from("foo"), privateKey);