diff --git a/deps/ncrypto/ncrypto.cc b/deps/ncrypto/ncrypto.cc index b3e6a57edc1b0e4..bccdb7971b604bb 100644 --- a/deps/ncrypto/ncrypto.cc +++ b/deps/ncrypto/ncrypto.cc @@ -2,6 +2,7 @@ #include #include #include "openssl/bn.h" +#include "openssl/evp.h" #if OPENSSL_VERSION_MAJOR >= 3 #include "openssl/provider.h" #endif @@ -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(u); + auto passphrase = static_cast*>(u); if (passphrase != nullptr) { size_t buflen = static_cast(size); size_t len = passphrase->len; @@ -220,4 +221,75 @@ 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. + length = std::string(input.data()).find_last_not_of(" \n\r\t") + 1; +#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 BIOPointer(); + +#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).find_last_not_of(" \n\r\t") + 1; +#endif + NetscapeSPKIPointer spki( + NETSCAPE_SPKI_b64_decode(input, length)); + if (!spki) return BIOPointer(); + + EVPKeyPointer pkey(NETSCAPE_SPKI_get_pubkey(spki.get())); + if (!pkey) return BIOPointer(); + + if (PEM_write_bio_PUBKEY(bio.get(), pkey.get()) <= 0) return BIOPointer(); + + return std::move(bio); +} + +Buffer 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(input).find_last_not_of(" \n\r\t") + 1; +#endif + NetscapeSPKIPointer sp( + NETSCAPE_SPKI_b64_decode(input, length)); + if (!sp) { + return Buffer { + .data = nullptr, + .len = 0, + }; + } + + unsigned char* buf = nullptr; + int buf_size = ASN1_STRING_to_UTF8(&buf, sp->spkac->challenge); + if (buf_size >= 0) { + return Buffer { + .data = reinterpret_cast(buf), + .len = static_cast(buf_size), + }; + } + return Buffer { + .data = nullptr, + .len = 0, + }; +} + } // namespace ncrypto diff --git a/deps/ncrypto/ncrypto.h b/deps/ncrypto/ncrypto.h index 6fb66fe5234d85b..c624577bdbc3a72 100644 --- a/deps/ncrypto/ncrypto.h +++ b/deps/ncrypto/ncrypto.h @@ -269,8 +269,9 @@ bool testFipsEnabled(); // ============================================================================ // Various utilities +template struct Buffer { - const void* data; + T* data; size_t len; }; @@ -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 +Buffer ExportChallenge(const char* input, size_t length); + // ============================================================================ // Version metadata #define NCRYPTO_VERSION "0.0.1" diff --git a/src/crypto/crypto_spkac.cc b/src/crypto/crypto_spkac.cc index a09a09ddd2f9d4f..236de520d8dbf29 100644 --- a/src/crypto/crypto_spkac.cc +++ b/src/crypto/crypto_spkac.cc @@ -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" @@ -16,25 +17,6 @@ using v8::Value; namespace crypto { namespace SPKAC { -bool VerifySpkac(const ArrayBufferOrViewContents& 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& args) { Environment* env = Environment::GetCurrent(args); @@ -44,31 +26,7 @@ void VerifySpkac(const FunctionCallbackInfo& 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& 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& args) { @@ -80,30 +38,13 @@ void ExportPublicKey(const FunctionCallbackInfo& 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())); } -ByteSource ExportChallenge(const ArrayBufferOrViewContents& 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& args) { Environment* env = Environment::GetCurrent(args); @@ -113,7 +54,8 @@ void ExportChallenge(const FunctionCallbackInfo& 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(); diff --git a/src/crypto/crypto_util.h b/src/crypto/crypto_util.h index 4d97af48edf6d5c..99a9ec33378d451 100644 --- a/src/crypto/crypto_util.h +++ b/src/crypto/crypto_util.h @@ -289,6 +289,12 @@ class ByteSource { v8::MaybeLocal ToBuffer(Environment* env); static ByteSource Allocated(void* data, size_t size); + + template + static ByteSource Allocated(const ncrypto::Buffer& buffer) { + return Allocated(buffer.data, buffer.len); + } + static ByteSource Foreign(const void* data, size_t size); static ByteSource FromEncodedString(Environment* env,