From 749c01157bb50debab2c4ca6693da01586537ff6 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Wed, 13 Nov 2024 11:26:14 -0800 Subject: [PATCH 1/2] Use BufferSource in Node.js X509Certificate --- src/workerd/api/crypto/x509.c++ | 38 ++++++++++++++++----------------- src/workerd/api/crypto/x509.h | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/workerd/api/crypto/x509.c++ b/src/workerd/api/crypto/x509.c++ index 7864e73b97c..2cd51ae162a 100644 --- a/src/workerd/api/crypto/x509.c++ +++ b/src/workerd/api/crypto/x509.c++ @@ -382,15 +382,15 @@ kj::String getExponentString(BIO* bio, const BIGNUM* e) { return toString(bio); } -kj::Array getRsaPubKey(RSA* rsa) { +jsg::BufferSource getRsaPubKey(jsg::Lock& js, RSA* rsa) { int size = i2d_RSA_PUBKEY(rsa, nullptr); KJ_ASSERT(size >= 0); - auto buf = kj::heapArray(size); - auto data = buf.begin(); + auto buf = jsg::BackingStore::alloc(js, size); + auto data = buf.asArrayPtr().begin(); KJ_ASSERT(i2d_RSA_PUBKEY(rsa, &data) >= 0); - return kj::mv(buf); + return jsg::BufferSource(js, kj::mv(buf)); } kj::Maybe getECGroupBits(const EC_GROUP* group) { @@ -402,21 +402,21 @@ kj::Maybe getECGroupBits(const EC_GROUP* group) { return bits; } -kj::Maybe> eCPointToBuffer( - const EC_GROUP* group, const EC_POINT* point, point_conversion_form_t form) { +kj::Maybe eCPointToBuffer( + jsg::Lock& js, const EC_GROUP* group, const EC_POINT* point, point_conversion_form_t form) { size_t len = EC_POINT_point2oct(group, point, form, nullptr, 0, nullptr); if (len == 0) { return kj::none; } - auto buffer = kj::heapArray(len); + auto buffer = jsg::BackingStore::alloc(js, len); - len = EC_POINT_point2oct(group, point, form, buffer.begin(), buffer.size(), nullptr); + len = EC_POINT_point2oct(group, point, form, buffer.asArrayPtr().begin(), buffer.size(), nullptr); if (len == 0) { return kj::none; } - return kj::mv(buffer); + return jsg::BufferSource(js, kj::mv(buffer)); } template @@ -428,11 +428,11 @@ kj::Maybe getCurveName(const int nid) { return kj::str(name); } -kj::Maybe> getECPubKey(const EC_GROUP* group, EC_KEY* ec) { +kj::Maybe getECPubKey(jsg::Lock& js, const EC_GROUP* group, EC_KEY* ec) { const EC_POINT* pubkey = EC_KEY_get0_public_key(ec); if (pubkey == nullptr) return kj::none; - return eCPointToBuffer(group, pubkey, EC_KEY_get_conv_form(ec)); + return eCPointToBuffer(js, group, pubkey, EC_KEY_get_conv_form(ec)); } template @@ -645,13 +645,13 @@ kj::Maybe> X509Certificate::getSerialNumber() { return kj::none; } -kj::Array X509Certificate::getRaw() { +jsg::BufferSource X509Certificate::getRaw(jsg::Lock& js) { ClearErrorOnReturn clearErrorOnReturn; int size = i2d_X509(cert_.get(), nullptr); - auto buf = kj::heapArray(size); - auto data = buf.begin(); + auto buf = jsg::BackingStore::alloc(js, size); + auto data = buf.asArrayPtr().begin(); KJ_REQUIRE(i2d_X509(cert_.get(), &data) >= 0); - return kj::mv(buf); + return jsg::BufferSource(js, kj::mv(buf)); } kj::Maybe> X509Certificate::getPublicKey() { @@ -786,7 +786,7 @@ jsg::JsObject X509Certificate::toLegacyObject(jsg::Lock& js) { obj.set(js, "modulus", js.str(getModulusString(bio.get(), RSA_get0_n(rsa)))); obj.set(js, "bits", js.num(RSA_bits(rsa))); obj.set(js, "exponent", js.str(getExponentString(bio.get(), RSA_get0_e(rsa)))); - obj.set(js, "pubkey", jsg::JsValue(js.bytes(getRsaPubKey(rsa)).getHandle(js))); + obj.set(js, "pubkey", jsg::JsValue(getRsaPubKey(js, rsa).getHandle(js))); break; } case EVP_PKEY_EC: { @@ -797,8 +797,8 @@ jsg::JsObject X509Certificate::toLegacyObject(jsg::Lock& js) { KJ_IF_SOME(bits, getECGroupBits(group)) { obj.set(js, "bits", js.num(bits)); } - KJ_IF_SOME(pubkey, getECPubKey(group, ec)) { - obj.set(js, "pubkey", jsg::JsValue(js.bytes(kj::mv(pubkey)).getHandle(js))); + KJ_IF_SOME(pubkey, getECPubKey(js, group, ec)) { + obj.set(js, "pubkey", jsg::JsValue(pubkey.getHandle(js))); } const int nid = EC_GROUP_get_curve_name(group); @@ -843,7 +843,7 @@ jsg::JsObject X509Certificate::toLegacyObject(jsg::Lock& js) { KJ_IF_SOME(serialNumber, getSerialNumber()) { obj.set(js, "serialNumber", js.str(serialNumber)); } - obj.set(js, "raw", jsg::JsValue(js.bytes(getRaw()).getHandle(js))); + obj.set(js, "raw", jsg::JsValue(getRaw(js).getHandle(js))); return obj; } diff --git a/src/workerd/api/crypto/x509.h b/src/workerd/api/crypto/x509.h index b5f1ed83b1a..6a57cf50543 100644 --- a/src/workerd/api/crypto/x509.h +++ b/src/workerd/api/crypto/x509.h @@ -23,7 +23,7 @@ class X509Certificate: public jsg::Object { kj::Maybe getValidTo(); kj::Maybe> getKeyUsage(); kj::Maybe> getSerialNumber(); - kj::Array getRaw(); + jsg::BufferSource getRaw(jsg::Lock& js); kj::Maybe> getPublicKey(); kj::Maybe getPem(); kj::Maybe getFingerprint(); From 47d103eb6205607da1114c387e9d94017ca0a332 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Wed, 13 Nov 2024 11:44:28 -0800 Subject: [PATCH 2/2] Update spkac to use BufferSource --- src/workerd/api/crypto/spkac.c++ | 24 +++++++++++++++--------- src/workerd/api/crypto/spkac.h | 6 ++++-- src/workerd/api/node/crypto.c++ | 10 ++++++---- src/workerd/api/node/crypto.h | 4 ++-- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/workerd/api/crypto/spkac.c++ b/src/workerd/api/crypto/spkac.c++ index a04191c6a17..da504279414 100644 --- a/src/workerd/api/crypto/spkac.c++ +++ b/src/workerd/api/crypto/spkac.c++ @@ -11,13 +11,13 @@ namespace workerd::api { namespace { -kj::Array toArray(BIO* bio) { +jsg::BufferSource toArray(jsg::Lock& js, BIO* bio) { BUF_MEM* bptr; BIO_get_mem_ptr(bio, &bptr); - auto buf = kj::heapArray(bptr->length); + auto buf = jsg::BackingStore::alloc(js, bptr->length); auto aptr = kj::arrayPtr(bptr->data, bptr->length); - buf.asPtr().copyFrom(aptr); - return buf.releaseAsBytes(); + buf.asArrayPtr().copyFrom(aptr); + return jsg::BufferSource(js, kj::mv(buf)); } kj::Maybe> tryGetSpki(kj::ArrayPtr input) { @@ -70,13 +70,13 @@ bool verifySpkac(kj::ArrayPtr input) { return false; } -kj::Maybe> exportPublicKey(kj::ArrayPtr input) { +kj::Maybe exportPublicKey(jsg::Lock& js, kj::ArrayPtr input) { ClearErrorOnReturn clearErrorOnReturn; KJ_IF_SOME(spki, tryGetSpki(input)) { KJ_IF_SOME(bio, tryNewBio()) { KJ_IF_SOME(key, tryOwnPkey(spki)) { if (PEM_write_bio_PUBKEY(bio.get(), key.get()) > 0) { - return toArray(bio.get()); + return toArray(js, bio.get()); } } } @@ -84,14 +84,20 @@ kj::Maybe> exportPublicKey(kj::ArrayPtr inpu return kj::none; } -kj::Maybe> exportChallenge(kj::ArrayPtr input) { +kj::Maybe exportChallenge(jsg::Lock& js, kj::ArrayPtr input) { ClearErrorOnReturn clearErrorOnReturn; KJ_IF_SOME(spki, tryGetSpki(input)) { kj::byte* buf = nullptr; + KJ_DEFER(OPENSSL_free(buf)); + int buf_size = ASN1_STRING_to_UTF8(&buf, spki->spkac->challenge); if (buf_size < 0 || buf == nullptr) return kj::none; - // Pay attention to how the buffer is freed below... - return kj::arrayPtr(buf, buf_size).attach(kj::defer([buf]() { OPENSSL_free(buf); })); + + auto dest = jsg::BackingStore::alloc(js, buf_size); + auto src = kj::arrayPtr(buf, buf_size); + dest.asArrayPtr().copyFrom(src); + + return jsg::BufferSource(js, kj::mv(dest)); } return kj::none; } diff --git a/src/workerd/api/crypto/spkac.h b/src/workerd/api/crypto/spkac.h index b415595d6e9..8dc79e44206 100644 --- a/src/workerd/api/crypto/spkac.h +++ b/src/workerd/api/crypto/spkac.h @@ -1,13 +1,15 @@ #pragma once +#include + #include namespace workerd::api { bool verifySpkac(kj::ArrayPtr input); -kj::Maybe> exportPublicKey(kj::ArrayPtr input); +kj::Maybe exportPublicKey(jsg::Lock& js, kj::ArrayPtr input); -kj::Maybe> exportChallenge(kj::ArrayPtr input); +kj::Maybe exportChallenge(jsg::Lock& js, kj::ArrayPtr input); } // namespace workerd::api diff --git a/src/workerd/api/node/crypto.c++ b/src/workerd/api/node/crypto.c++ index 17d122d19af..649fd0d1d97 100644 --- a/src/workerd/api/node/crypto.c++ +++ b/src/workerd/api/node/crypto.c++ @@ -93,12 +93,14 @@ bool CryptoImpl::verifySpkac(kj::Array input) { return workerd::api::verifySpkac(input); } -kj::Maybe> CryptoImpl::exportPublicKey(kj::Array input) { - return workerd::api::exportPublicKey(input); +kj::Maybe CryptoImpl::exportPublicKey( + jsg::Lock& js, kj::Array input) { + return workerd::api::exportPublicKey(js, input); } -kj::Maybe> CryptoImpl::exportChallenge(kj::Array input) { - return workerd::api::exportChallenge(input); +kj::Maybe CryptoImpl::exportChallenge( + jsg::Lock& js, kj::Array input) { + return workerd::api::exportChallenge(js, input); } kj::Array CryptoImpl::randomPrime(uint32_t size, diff --git a/src/workerd/api/node/crypto.h b/src/workerd/api/node/crypto.h index 55431fa9cbc..cdc16e26aa6 100644 --- a/src/workerd/api/node/crypto.h +++ b/src/workerd/api/node/crypto.h @@ -208,8 +208,8 @@ class CryptoImpl final: public jsg::Object { jsg::Ref createPublicKey(jsg::Lock& js, CreateAsymmetricKeyOptions options); bool verifySpkac(kj::Array input); - kj::Maybe> exportPublicKey(kj::Array input); - kj::Maybe> exportChallenge(kj::Array input); + kj::Maybe exportPublicKey(jsg::Lock& js, kj::Array input); + kj::Maybe exportChallenge(jsg::Lock& js, kj::Array input); JSG_RESOURCE_TYPE(CryptoImpl) { // DH