Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: move spkac methods to ncrypto #53985

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 70 additions & 1 deletion deps/ncrypto/ncrypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <algorithm>
#include <cstring>
#include "openssl/bn.h"
#include "openssl/evp.h"
#if OPENSSL_VERSION_MAJOR >= 3
#include "openssl/provider.h"
#endif
Expand Down Expand Up @@ -207,7 +208,7 @@ int NoPasswordCallback(char* buf, int size, int rwflag, void* u) {
}

int PasswordCallback(char* buf, int size, int rwflag, void* u) {
const Buffer* passphrase = static_cast<const Buffer*>(u);
auto passphrase = static_cast<const Buffer<char>*>(u);
if (passphrase != nullptr) {
size_t buflen = static_cast<size_t>(size);
size_t len = passphrase->len;
Expand All @@ -220,4 +221,72 @@ int PasswordCallback(char* buf, int size, int rwflag, void* u) {
return -1;
}

// ============================================================================
// SPKAC

bool VerifySpkac(const char* input, size_t length) {
#ifdef OPENSSL_IS_BORINGSSL
// OpenSSL uses EVP_DecodeBlock, which explicitly removes trailing characters,
// while BoringSSL uses EVP_DecodedLength and EVP_DecodeBase64, which do not.
// As such, we trim those characters here for compatibility.
//
// find_last_not_of can return npos, which is the maximum value of size_t.
// The + 1 will force a roll-ver to 0, which is the correct value. in that
// case.
length = std::string_view(input, length).find_last_not_of(" \n\r\t") + 1;
anonrig marked this conversation as resolved.
Show resolved Hide resolved
#endif
NetscapeSPKIPointer spki(
NETSCAPE_SPKI_b64_decode(input, length));
if (!spki)
return false;

EVPKeyPointer pkey(X509_PUBKEY_get(spki->spkac->pubkey));
return pkey ? NETSCAPE_SPKI_verify(spki.get(), pkey.get()) > 0 : false;
}

BIOPointer ExportPublicKey(const char* input, size_t length) {
BIOPointer bio(BIO_new(BIO_s_mem()));
if (!bio) return {};

#ifdef OPENSSL_IS_BORINGSSL
// OpenSSL uses EVP_DecodeBlock, which explicitly removes trailing characters,
// while BoringSSL uses EVP_DecodedLength and EVP_DecodeBase64, which do not.
// As such, we trim those characters here for compatibility.
length = std::string_view(input, length).find_last_not_of(" \n\r\t") + 1;
#endif
NetscapeSPKIPointer spki(
NETSCAPE_SPKI_b64_decode(input, length));
if (!spki) return {};

EVPKeyPointer pkey(NETSCAPE_SPKI_get_pubkey(spki.get()));
if (!pkey) return {};

if (PEM_write_bio_PUBKEY(bio.get(), pkey.get()) <= 0) return { };

return std::move(bio);
}

Buffer<char> ExportChallenge(const char* input, size_t length) {
#ifdef OPENSSL_IS_BORINGSSL
// OpenSSL uses EVP_DecodeBlock, which explicitly removes trailing characters,
// while BoringSSL uses EVP_DecodedLength and EVP_DecodeBase64, which do not.
// As such, we trim those characters here for compatibility.
length = std::string_view(input, length).find_last_not_of(" \n\r\t") + 1;
#endif
NetscapeSPKIPointer sp(
NETSCAPE_SPKI_b64_decode(input, length));
if (!sp) return {};

unsigned char* buf = nullptr;
int buf_size = ASN1_STRING_to_UTF8(&buf, sp->spkac->challenge);
if (buf_size >= 0) {
return {
.data = reinterpret_cast<char*>(buf),
.len = static_cast<size_t>(buf_size),
};
}

return {};
}

} // namespace ncrypto
14 changes: 12 additions & 2 deletions deps/ncrypto/ncrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,9 +269,10 @@ bool testFipsEnabled();
// ============================================================================
// Various utilities

template <typename T>
struct Buffer {
const void* data;
size_t len;
T* data = nullptr;
size_t len = 0;
};

bool CSPRNG(void* buffer, size_t length) NCRYPTO_MUST_USE_RESULT;
Expand All @@ -285,6 +286,15 @@ int NoPasswordCallback(char* buf, int size, int rwflag, void* u);

int PasswordCallback(char* buf, int size, int rwflag, void* u);

// ============================================================================
// SPKAC

bool VerifySpkac(const char* input, size_t length);
BIOPointer ExportPublicKey(const char* input, size_t length);

// The caller takes ownership of the returned Buffer<char>
Buffer<char> ExportChallenge(const char* input, size_t length);

// ============================================================================
// Version metadata
#define NCRYPTO_VERSION "0.0.1"
Expand Down
72 changes: 7 additions & 65 deletions src/crypto/crypto_spkac.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "crypto/crypto_util.h"
#include "env-inl.h"
#include "memory_tracker-inl.h"
#include "ncrypto.h"
#include "node.h"
#include "v8.h"

Expand All @@ -16,25 +17,6 @@ using v8::Value;

namespace crypto {
namespace SPKAC {
bool VerifySpkac(const ArrayBufferOrViewContents<char>& input) {
size_t length = input.size();
#ifdef OPENSSL_IS_BORINGSSL
// OpenSSL uses EVP_DecodeBlock, which explicitly removes trailing characters,
// while BoringSSL uses EVP_DecodedLength and EVP_DecodeBase64, which do not.
// As such, we trim those characters here for compatibility.
length = std::string(input.data()).find_last_not_of(" \n\r\t") + 1;
#endif
NetscapeSPKIPointer spki(
NETSCAPE_SPKI_b64_decode(input.data(), length));
if (!spki)
return false;

EVPKeyPointer pkey(X509_PUBKEY_get(spki->spkac->pubkey));
if (!pkey)
return false;

return NETSCAPE_SPKI_verify(spki.get(), pkey.get()) > 0;
}

void VerifySpkac(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Expand All @@ -44,31 +26,7 @@ void VerifySpkac(const FunctionCallbackInfo<Value>& args) {
if (UNLIKELY(!input.CheckSizeInt32()))
return THROW_ERR_OUT_OF_RANGE(env, "spkac is too large");

args.GetReturnValue().Set(VerifySpkac(input));
}

ByteSource ExportPublicKey(Environment* env,
const ArrayBufferOrViewContents<char>& input) {
BIOPointer bio(BIO_new(BIO_s_mem()));
if (!bio) return ByteSource();

size_t length = input.size();
#ifdef OPENSSL_IS_BORINGSSL
// OpenSSL uses EVP_DecodeBlock, which explicitly removes trailing characters,
// while BoringSSL uses EVP_DecodedLength and EVP_DecodeBase64, which do not.
// As such, we trim those characters here for compatibility.
length = std::string(input.data()).find_last_not_of(" \n\r\t") + 1;
#endif
NetscapeSPKIPointer spki(
NETSCAPE_SPKI_b64_decode(input.data(), length));
if (!spki) return ByteSource();

EVPKeyPointer pkey(NETSCAPE_SPKI_get_pubkey(spki.get()));
if (!pkey) return ByteSource();

if (PEM_write_bio_PUBKEY(bio.get(), pkey.get()) <= 0) return ByteSource();

return ByteSource::FromBIO(bio);
args.GetReturnValue().Set(ncrypto::VerifySpkac(input.data(), input.size()));
}

void ExportPublicKey(const FunctionCallbackInfo<Value>& args) {
Expand All @@ -80,30 +38,13 @@ void ExportPublicKey(const FunctionCallbackInfo<Value>& args) {
if (UNLIKELY(!input.CheckSizeInt32()))
return THROW_ERR_OUT_OF_RANGE(env, "spkac is too large");

ByteSource pkey = ExportPublicKey(env, input);
if (!pkey) return args.GetReturnValue().SetEmptyString();
BIOPointer bio = ncrypto::ExportPublicKey(input.data(), input.size());
if (!bio) return args.GetReturnValue().SetEmptyString();

auto pkey = ByteSource::FromBIO(bio);
args.GetReturnValue().Set(pkey.ToBuffer(env).FromMaybe(Local<Value>()));
}

ByteSource ExportChallenge(const ArrayBufferOrViewContents<char>& input) {
size_t length = input.size();
#ifdef OPENSSL_IS_BORINGSSL
// OpenSSL uses EVP_DecodeBlock, which explicitly removes trailing characters,
// while BoringSSL uses EVP_DecodedLength and EVP_DecodeBase64, which do not.
// As such, we trim those characters here for compatibility.
length = std::string(input.data()).find_last_not_of(" \n\r\t") + 1;
#endif
NetscapeSPKIPointer sp(
NETSCAPE_SPKI_b64_decode(input.data(), length));
if (!sp)
return ByteSource();

unsigned char* buf = nullptr;
int buf_size = ASN1_STRING_to_UTF8(&buf, sp->spkac->challenge);
return (buf_size >= 0) ? ByteSource::Allocated(buf, buf_size) : ByteSource();
}

void ExportChallenge(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

Expand All @@ -113,7 +54,8 @@ void ExportChallenge(const FunctionCallbackInfo<Value>& args) {
if (UNLIKELY(!input.CheckSizeInt32()))
return THROW_ERR_OUT_OF_RANGE(env, "spkac is too large");

ByteSource cert = ExportChallenge(input);
auto cert = ByteSource::Allocated(
ncrypto::ExportChallenge(input.data(), input.size()));
if (!cert)
return args.GetReturnValue().SetEmptyString();

Expand Down
6 changes: 6 additions & 0 deletions src/crypto/crypto_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,12 @@ class ByteSource {
v8::MaybeLocal<v8::Uint8Array> ToBuffer(Environment* env);

static ByteSource Allocated(void* data, size_t size);

template <typename T>
static ByteSource Allocated(const ncrypto::Buffer<T>& buffer) {
return Allocated(buffer.data, buffer.len);
}

static ByteSource Foreign(const void* data, size_t size);

static ByteSource FromEncodedString(Environment* env,
Expand Down
Loading