Skip to content

Commit

Permalink
Merge pull request #3106 from cloudflare/jsnell/node-x509-use-buffers…
Browse files Browse the repository at this point in the history
…ource
  • Loading branch information
jasnell authored Nov 13, 2024
2 parents c8cfeda + 47d103e commit 158d137
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 37 deletions.
24 changes: 15 additions & 9 deletions src/workerd/api/crypto/spkac.c++
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@

namespace workerd::api {
namespace {
kj::Array<kj::byte> toArray(BIO* bio) {
jsg::BufferSource toArray(jsg::Lock& js, BIO* bio) {
BUF_MEM* bptr;
BIO_get_mem_ptr(bio, &bptr);
auto buf = kj::heapArray<char>(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<char>().copyFrom(aptr);
return jsg::BufferSource(js, kj::mv(buf));
}

kj::Maybe<kj::Own<NETSCAPE_SPKI>> tryGetSpki(kj::ArrayPtr<const kj::byte> input) {
Expand Down Expand Up @@ -70,28 +70,34 @@ bool verifySpkac(kj::ArrayPtr<const kj::byte> input) {
return false;
}

kj::Maybe<kj::Array<kj::byte>> exportPublicKey(kj::ArrayPtr<const kj::byte> input) {
kj::Maybe<jsg::BufferSource> exportPublicKey(jsg::Lock& js, kj::ArrayPtr<const kj::byte> 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());
}
}
}
}
return kj::none;
}

kj::Maybe<kj::Array<kj::byte>> exportChallenge(kj::ArrayPtr<const kj::byte> input) {
kj::Maybe<jsg::BufferSource> exportChallenge(jsg::Lock& js, kj::ArrayPtr<const kj::byte> 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;
}
Expand Down
6 changes: 4 additions & 2 deletions src/workerd/api/crypto/spkac.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
#pragma once

#include <workerd/jsg/jsg.h>

#include <kj/common.h>

namespace workerd::api {

bool verifySpkac(kj::ArrayPtr<const kj::byte> input);

kj::Maybe<kj::Array<kj::byte>> exportPublicKey(kj::ArrayPtr<const kj::byte> input);
kj::Maybe<jsg::BufferSource> exportPublicKey(jsg::Lock& js, kj::ArrayPtr<const kj::byte> input);

kj::Maybe<kj::Array<kj::byte>> exportChallenge(kj::ArrayPtr<const kj::byte> input);
kj::Maybe<jsg::BufferSource> exportChallenge(jsg::Lock& js, kj::ArrayPtr<const kj::byte> input);

} // namespace workerd::api
38 changes: 19 additions & 19 deletions src/workerd/api/crypto/x509.c++
Original file line number Diff line number Diff line change
Expand Up @@ -382,15 +382,15 @@ kj::String getExponentString(BIO* bio, const BIGNUM* e) {
return toString(bio);
}

kj::Array<kj::byte> 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<kj::byte>(size);
auto data = buf.begin();
auto buf = jsg::BackingStore::alloc<v8::Uint8Array>(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<int32_t> getECGroupBits(const EC_GROUP* group) {
Expand All @@ -402,21 +402,21 @@ kj::Maybe<int32_t> getECGroupBits(const EC_GROUP* group) {
return bits;
}

kj::Maybe<kj::Array<kj::byte>> eCPointToBuffer(
const EC_GROUP* group, const EC_POINT* point, point_conversion_form_t form) {
kj::Maybe<jsg::BufferSource> 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<kj::byte>(len);
auto buffer = jsg::BackingStore::alloc<v8::Uint8Array>(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 <const char* (*nid2string)(int nid)>
Expand All @@ -428,11 +428,11 @@ kj::Maybe<kj::String> getCurveName(const int nid) {
return kj::str(name);
}

kj::Maybe<kj::Array<kj::byte>> getECPubKey(const EC_GROUP* group, EC_KEY* ec) {
kj::Maybe<jsg::BufferSource> 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 <X509_NAME* get_name(const X509*)>
Expand Down Expand Up @@ -645,13 +645,13 @@ kj::Maybe<kj::Array<const char>> X509Certificate::getSerialNumber() {
return kj::none;
}

kj::Array<kj::byte> X509Certificate::getRaw() {
jsg::BufferSource X509Certificate::getRaw(jsg::Lock& js) {
ClearErrorOnReturn clearErrorOnReturn;
int size = i2d_X509(cert_.get(), nullptr);
auto buf = kj::heapArray<kj::byte>(size);
auto data = buf.begin();
auto buf = jsg::BackingStore::alloc<v8::Uint8Array>(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<jsg::Ref<CryptoKey>> X509Certificate::getPublicKey() {
Expand Down Expand Up @@ -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: {
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion src/workerd/api/crypto/x509.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class X509Certificate: public jsg::Object {
kj::Maybe<kj::String> getValidTo();
kj::Maybe<kj::Array<kj::String>> getKeyUsage();
kj::Maybe<kj::Array<const char>> getSerialNumber();
kj::Array<kj::byte> getRaw();
jsg::BufferSource getRaw(jsg::Lock& js);
kj::Maybe<jsg::Ref<CryptoKey>> getPublicKey();
kj::Maybe<kj::String> getPem();
kj::Maybe<kj::String> getFingerprint();
Expand Down
10 changes: 6 additions & 4 deletions src/workerd/api/node/crypto.c++
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,14 @@ bool CryptoImpl::verifySpkac(kj::Array<const kj::byte> input) {
return workerd::api::verifySpkac(input);
}

kj::Maybe<kj::Array<kj::byte>> CryptoImpl::exportPublicKey(kj::Array<const kj::byte> input) {
return workerd::api::exportPublicKey(input);
kj::Maybe<jsg::BufferSource> CryptoImpl::exportPublicKey(
jsg::Lock& js, kj::Array<const kj::byte> input) {
return workerd::api::exportPublicKey(js, input);
}

kj::Maybe<kj::Array<kj::byte>> CryptoImpl::exportChallenge(kj::Array<const kj::byte> input) {
return workerd::api::exportChallenge(input);
kj::Maybe<jsg::BufferSource> CryptoImpl::exportChallenge(
jsg::Lock& js, kj::Array<const kj::byte> input) {
return workerd::api::exportChallenge(js, input);
}

kj::Array<kj::byte> CryptoImpl::randomPrime(uint32_t size,
Expand Down
4 changes: 2 additions & 2 deletions src/workerd/api/node/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ class CryptoImpl final: public jsg::Object {
jsg::Ref<CryptoKey> createPublicKey(jsg::Lock& js, CreateAsymmetricKeyOptions options);

bool verifySpkac(kj::Array<const kj::byte> input);
kj::Maybe<kj::Array<kj::byte>> exportPublicKey(kj::Array<const kj::byte> input);
kj::Maybe<kj::Array<kj::byte>> exportChallenge(kj::Array<const kj::byte> input);
kj::Maybe<jsg::BufferSource> exportPublicKey(jsg::Lock& js, kj::Array<const kj::byte> input);
kj::Maybe<jsg::BufferSource> exportChallenge(jsg::Lock& js, kj::Array<const kj::byte> input);

JSG_RESOURCE_TYPE(CryptoImpl) {
// DH
Expand Down

0 comments on commit 158d137

Please sign in to comment.