From 5e72bd3545144295869325868fae5f8b5ed3cb69 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Tue, 3 Sep 2024 17:20:36 -0700 Subject: [PATCH] src: eliminate ManagedEVPPkey Prior to this change, the ManagedEVPPkey class added an additional layer of abstraction to the EVP_PKEY class that wasn't strictly necessary. Previously we had: KeyObjectHandle -> std::shared_ptr -> ManagedEVPPkey -> EVPKeyPointer After this change we have: KeyObjectHandle -> KeyObjectData -> EVPKeyPointer The `KeyObjectData` class no longer needs to be wrapped in std::shared_ptr but it will hold the underlying EVPKeyPointer in a std::shared_ptr. This greatly simplifies the abstraction and provides an overall reduction in code and complexity, although the changeset in this PR is fairly extensive to get there. This refactor is being done to simplify the codebase as part of the process of extracting crypto functionality to the separate ncrypto dep. PR-URL: https://github.com/nodejs/node/pull/54751 Reviewed-By: Yagiz Nizipli --- src/crypto/README.md | 7 +- src/crypto/crypto_aes.cc | 66 +++--- src/crypto/crypto_aes.h | 13 +- src/crypto/crypto_cipher.cc | 7 +- src/crypto/crypto_cipher.h | 38 ++-- src/crypto/crypto_context.cc | 7 +- src/crypto/crypto_context.h | 2 +- src/crypto/crypto_dh.cc | 49 ++--- src/crypto/crypto_dh.h | 20 +- src/crypto/crypto_dsa.cc | 23 +- src/crypto/crypto_dsa.h | 16 +- src/crypto/crypto_ec.cc | 108 +++++----- src/crypto/crypto_ec.h | 38 ++-- src/crypto/crypto_hkdf.cc | 8 +- src/crypto/crypto_hkdf.h | 2 +- src/crypto/crypto_hmac.cc | 16 +- src/crypto/crypto_hmac.h | 2 +- src/crypto/crypto_keygen.cc | 3 +- src/crypto/crypto_keygen.h | 24 +-- src/crypto/crypto_keys.cc | 398 ++++++++++++++++------------------- src/crypto/crypto_keys.h | 173 ++++++++------- src/crypto/crypto_rsa.cc | 101 +++++---- src/crypto/crypto_rsa.h | 40 ++-- src/crypto/crypto_sig.cc | 103 ++++----- src/crypto/crypto_sig.h | 13 +- src/crypto/crypto_util.cc | 4 +- src/crypto/crypto_x509.cc | 15 +- src/quic/tlscontext.cc | 17 +- src/quic/tlscontext.h | 2 +- 29 files changed, 603 insertions(+), 712 deletions(-) diff --git a/src/crypto/README.md b/src/crypto/README.md index e761f156d189d6..53f64ba22d8261 100644 --- a/src/crypto/README.md +++ b/src/crypto/README.md @@ -149,15 +149,10 @@ threadpool). Refer to `crypto_keys.h` and `crypto_keys.cc` for all code relating to the core key objects. -#### `ManagedEVPPKey` - -The `ManagedEVPPKey` class is a smart pointer for OpenSSL `EVP_PKEY` -structures. These manage the lifecycle of Public and Private key pairs. - #### `KeyObjectData` `KeyObjectData` is an internal thread-safe structure used to wrap either -a `ManagedEVPPKey` (for Public or Private keys) or a `ByteSource` containing +a `EVPKeyPointer` (for Public or Private keys) or a `ByteSource` containing a Secret key. #### `KeyObjectHandle` diff --git a/src/crypto/crypto_aes.cc b/src/crypto/crypto_aes.cc index f9f9a73d46dbb1..ebf7157eb21898 100644 --- a/src/crypto/crypto_aes.cc +++ b/src/crypto/crypto_aes.cc @@ -31,15 +31,13 @@ namespace { // The key_data must be a secret key. // On success, this function sets out to a new ByteSource // instance containing the results and returns WebCryptoCipherStatus::OK. -WebCryptoCipherStatus AES_Cipher( - Environment* env, - KeyObjectData* key_data, - WebCryptoCipherMode cipher_mode, - const AESCipherConfig& params, - const ByteSource& in, - ByteSource* out) { - CHECK_NOT_NULL(key_data); - CHECK_EQ(key_data->GetKeyType(), kKeyTypeSecret); +WebCryptoCipherStatus AES_Cipher(Environment* env, + const KeyObjectData& key_data, + WebCryptoCipherMode cipher_mode, + const AESCipherConfig& params, + const ByteSource& in, + ByteSource* out) { + CHECK_EQ(key_data.GetKeyType(), kKeyTypeSecret); const int mode = EVP_CIPHER_mode(params.cipher); @@ -69,14 +67,13 @@ WebCryptoCipherStatus AES_Cipher( return WebCryptoCipherStatus::FAILED; } - if (!EVP_CIPHER_CTX_set_key_length( - ctx.get(), - key_data->GetSymmetricKeySize()) || + if (!EVP_CIPHER_CTX_set_key_length(ctx.get(), + key_data.GetSymmetricKeySize()) || !EVP_CipherInit_ex( ctx.get(), nullptr, nullptr, - reinterpret_cast(key_data->GetSymmetricKey()), + reinterpret_cast(key_data.GetSymmetricKey()), params.iv.data(), encrypt)) { return WebCryptoCipherStatus::FAILED; @@ -217,13 +214,12 @@ std::vector BlockWithZeroedCounter( return new_counter_block; } -WebCryptoCipherStatus AES_CTR_Cipher2( - KeyObjectData* key_data, - WebCryptoCipherMode cipher_mode, - const AESCipherConfig& params, - const ByteSource& in, - unsigned const char* counter, - unsigned char* out) { +WebCryptoCipherStatus AES_CTR_Cipher2(const KeyObjectData& key_data, + WebCryptoCipherMode cipher_mode, + const AESCipherConfig& params, + const ByteSource& in, + unsigned const char* counter, + unsigned char* out) { CipherCtxPointer ctx(EVP_CIPHER_CTX_new()); const bool encrypt = cipher_mode == kWebCryptoCipherEncrypt; @@ -231,7 +227,7 @@ WebCryptoCipherStatus AES_CTR_Cipher2( ctx.get(), params.cipher, nullptr, - reinterpret_cast(key_data->GetSymmetricKey()), + reinterpret_cast(key_data.GetSymmetricKey()), counter, encrypt)) { // Cipher init failed @@ -259,13 +255,12 @@ WebCryptoCipherStatus AES_CTR_Cipher2( return WebCryptoCipherStatus::OK; } -WebCryptoCipherStatus AES_CTR_Cipher( - Environment* env, - KeyObjectData* key_data, - WebCryptoCipherMode cipher_mode, - const AESCipherConfig& params, - const ByteSource& in, - ByteSource* out) { +WebCryptoCipherStatus AES_CTR_Cipher(Environment* env, + const KeyObjectData& key_data, + WebCryptoCipherMode cipher_mode, + const AESCipherConfig& params, + const ByteSource& in, + ByteSource* out) { auto num_counters = BignumPointer::New(); if (!BN_lshift(num_counters.get(), BignumPointer::One(), params.length)) return WebCryptoCipherStatus::FAILED; @@ -518,16 +513,15 @@ Maybe AESCipherTraits::AdditionalConfig( return Just(true); } -WebCryptoCipherStatus AESCipherTraits::DoCipher( - Environment* env, - std::shared_ptr key_data, - WebCryptoCipherMode cipher_mode, - const AESCipherConfig& params, - const ByteSource& in, - ByteSource* out) { +WebCryptoCipherStatus AESCipherTraits::DoCipher(Environment* env, + const KeyObjectData& key_data, + WebCryptoCipherMode cipher_mode, + const AESCipherConfig& params, + const ByteSource& in, + ByteSource* out) { #define V(name, fn, _) \ case kKeyVariantAES_##name: \ - return fn(env, key_data.get(), cipher_mode, params, in, out); + return fn(env, key_data, cipher_mode, params, in, out); switch (params.variant) { VARIANTS(V) default: diff --git a/src/crypto/crypto_aes.h b/src/crypto/crypto_aes.h index a9ec45c26606de..1de8d8ab8cabca 100644 --- a/src/crypto/crypto_aes.h +++ b/src/crypto/crypto_aes.h @@ -67,13 +67,12 @@ struct AESCipherTraits final { WebCryptoCipherMode cipher_mode, AESCipherConfig* config); - static WebCryptoCipherStatus DoCipher( - Environment* env, - std::shared_ptr key_data, - WebCryptoCipherMode cipher_mode, - const AESCipherConfig& params, - const ByteSource& in, - ByteSource* out); + static WebCryptoCipherStatus DoCipher(Environment* env, + const KeyObjectData& key_data, + WebCryptoCipherMode cipher_mode, + const AESCipherConfig& params, + const ByteSource& in, + ByteSource* out); }; using AESCryptoJob = CipherJob; diff --git a/src/crypto/crypto_cipher.cc b/src/crypto/crypto_cipher.cc index f7ff786d652318..fe35a8e0f6bbb7 100644 --- a/src/crypto/crypto_cipher.cc +++ b/src/crypto/crypto_cipher.cc @@ -990,7 +990,7 @@ template bool PublicKeyCipher::Cipher( Environment* env, - const ManagedEVPPKey& pkey, + const EVPKeyPointer& pkey, int padding, const EVP_MD* digest, const ArrayBufferOrViewContents& oaep_label, @@ -1057,8 +1057,9 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); unsigned int offset = 0; - ManagedEVPPKey pkey = - ManagedEVPPKey::GetPublicOrPrivateKeyFromJs(args, &offset); + auto data = KeyObjectData::GetPublicOrPrivateKeyFromJs(args, &offset); + if (!data) return; + const auto& pkey = data.GetAsymmetricKey(); if (!pkey) return; diff --git a/src/crypto/crypto_cipher.h b/src/crypto/crypto_cipher.h index e725a2f30dc6b0..091ae0445572c7 100644 --- a/src/crypto/crypto_cipher.h +++ b/src/crypto/crypto_cipher.h @@ -110,7 +110,7 @@ class PublicKeyCipher { EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init, EVP_PKEY_cipher_t EVP_PKEY_cipher> static bool Cipher(Environment* env, - const ManagedEVPPKey& pkey, + const EVPKeyPointer& pkey, int padding, const EVP_MD* digest, const ArrayBufferOrViewContents& oaep_label, @@ -195,27 +195,23 @@ class CipherJob final : public CryptoJob { CryptoJob::RegisterExternalReferences(New, registry); } - CipherJob( - Environment* env, - v8::Local object, - CryptoJobMode mode, - KeyObjectHandle* key, - WebCryptoCipherMode cipher_mode, - const ArrayBufferOrViewContents& data, - AdditionalParams&& params) - : CryptoJob( - env, - object, - AsyncWrap::PROVIDER_CIPHERREQUEST, - mode, - std::move(params)), - key_(key->Data()), + CipherJob(Environment* env, + v8::Local object, + CryptoJobMode mode, + KeyObjectHandle* key, + WebCryptoCipherMode cipher_mode, + const ArrayBufferOrViewContents& data, + AdditionalParams&& params) + : CryptoJob(env, + object, + AsyncWrap::PROVIDER_CIPHERREQUEST, + mode, + std::move(params)), + key_(key->Data().addRef()), cipher_mode_(cipher_mode), - in_(mode == kCryptoJobAsync - ? data.ToCopy() - : data.ToByteSource()) {} + in_(mode == kCryptoJobAsync ? data.ToCopy() : data.ToByteSource()) {} - std::shared_ptr key() const { return key_; } + const KeyObjectData& key() const { return key_; } WebCryptoCipherMode cipher_mode() const { return cipher_mode_; } @@ -278,7 +274,7 @@ class CipherJob final : public CryptoJob { } private: - std::shared_ptr key_; + KeyObjectData key_; WebCryptoCipherMode cipher_mode_; ByteSource in_; ByteSource out_; diff --git a/src/crypto/crypto_context.cc b/src/crypto/crypto_context.cc index ea7be16fa73dd9..c924a54639e8c2 100644 --- a/src/crypto/crypto_context.cc +++ b/src/crypto/crypto_context.cc @@ -613,15 +613,14 @@ void SecureContext::SetKeylogCallback(KeylogCb cb) { SSL_CTX_set_keylog_callback(ctx_.get(), cb); } -Maybe SecureContext::UseKey(Environment* env, - std::shared_ptr key) { - if (key->GetKeyType() != KeyType::kKeyTypePrivate) { +Maybe SecureContext::UseKey(Environment* env, const KeyObjectData& key) { + if (key.GetKeyType() != KeyType::kKeyTypePrivate) { THROW_ERR_CRYPTO_INVALID_KEYTYPE(env); return Nothing(); } ClearErrorOnReturn clear_error_on_return; - if (!SSL_CTX_use_PrivateKey(ctx_.get(), key->GetAsymmetricKey().get())) { + if (!SSL_CTX_use_PrivateKey(ctx_.get(), key.GetAsymmetricKey().get())) { ThrowCryptoError(env, ERR_get_error(), "SSL_CTX_use_PrivateKey"); return Nothing(); } diff --git a/src/crypto/crypto_context.h b/src/crypto/crypto_context.h index c6c10b1426ac6b..7ba6a5441300fc 100644 --- a/src/crypto/crypto_context.h +++ b/src/crypto/crypto_context.h @@ -59,7 +59,7 @@ class SecureContext final : public BaseObject { v8::Maybe AddCert(Environment* env, BIOPointer&& bio); v8::Maybe SetCRL(Environment* env, const BIOPointer& bio); - v8::Maybe UseKey(Environment* env, std::shared_ptr key); + v8::Maybe UseKey(Environment* env, const KeyObjectData& key); void SetCACert(const BIOPointer& bio); void SetRootCerts(); diff --git a/src/crypto/crypto_dh.cc b/src/crypto/crypto_dh.cc index 1203cc469413cb..f277b52c3a0817 100644 --- a/src/crypto/crypto_dh.cc +++ b/src/crypto/crypto_dh.cc @@ -432,30 +432,30 @@ Maybe DHKeyExportTraits::AdditionalConfig( } WebCryptoKeyExportStatus DHKeyExportTraits::DoExport( - std::shared_ptr key_data, + const KeyObjectData& key_data, WebCryptoKeyFormat format, const DHKeyExportConfig& params, ByteSource* out) { - CHECK_NE(key_data->GetKeyType(), kKeyTypeSecret); + CHECK_NE(key_data.GetKeyType(), kKeyTypeSecret); switch (format) { case kWebCryptoKeyFormatPKCS8: - if (key_data->GetKeyType() != kKeyTypePrivate) + if (key_data.GetKeyType() != kKeyTypePrivate) return WebCryptoKeyExportStatus::INVALID_KEY_TYPE; - return PKEY_PKCS8_Export(key_data.get(), out); + return PKEY_PKCS8_Export(key_data, out); case kWebCryptoKeyFormatSPKI: - if (key_data->GetKeyType() != kKeyTypePublic) + if (key_data.GetKeyType() != kKeyTypePublic) return WebCryptoKeyExportStatus::INVALID_KEY_TYPE; - return PKEY_SPKI_Export(key_data.get(), out); + return PKEY_SPKI_Export(key_data, out); default: UNREACHABLE(); } } namespace { -ByteSource StatelessDiffieHellmanThreadsafe(const ManagedEVPPKey& our_key, - const ManagedEVPPKey& their_key) { - auto dp = DHPointer::stateless(our_key.pkey(), their_key.pkey()); +ByteSource StatelessDiffieHellmanThreadsafe(const EVPKeyPointer& our_key, + const EVPKeyPointer& their_key) { + auto dp = DHPointer::stateless(our_key, their_key); if (!dp) return {}; return ByteSource::Allocated(dp.release()); @@ -467,13 +467,13 @@ void Stateless(const FunctionCallbackInfo& args) { CHECK(args[0]->IsObject() && args[1]->IsObject()); KeyObjectHandle* our_key_object; ASSIGN_OR_RETURN_UNWRAP(&our_key_object, args[0].As()); - CHECK_EQ(our_key_object->Data()->GetKeyType(), kKeyTypePrivate); + CHECK_EQ(our_key_object->Data().GetKeyType(), kKeyTypePrivate); KeyObjectHandle* their_key_object; ASSIGN_OR_RETURN_UNWRAP(&their_key_object, args[1].As()); - CHECK_NE(their_key_object->Data()->GetKeyType(), kKeyTypeSecret); + CHECK_NE(their_key_object->Data().GetKeyType(), kKeyTypeSecret); - ManagedEVPPKey our_key = our_key_object->Data()->GetAsymmetricKey(); - ManagedEVPPKey their_key = their_key_object->Data()->GetAsymmetricKey(); + const auto& our_key = our_key_object->Data().GetAsymmetricKey(); + const auto& their_key = their_key_object->Data().GetAsymmetricKey(); Local out; if (!StatelessDiffieHellmanThreadsafe(our_key, their_key) @@ -503,14 +503,14 @@ Maybe DHBitsTraits::AdditionalConfig( ASSIGN_OR_RETURN_UNWRAP(&public_key, args[offset], Nothing()); ASSIGN_OR_RETURN_UNWRAP(&private_key, args[offset + 1], Nothing()); - if (private_key->Data()->GetKeyType() != kKeyTypePrivate || - public_key->Data()->GetKeyType() != kKeyTypePublic) { + if (private_key->Data().GetKeyType() != kKeyTypePrivate || + public_key->Data().GetKeyType() != kKeyTypePublic) { THROW_ERR_CRYPTO_INVALID_KEYTYPE(env); return Nothing(); } - params->public_key = public_key->Data(); - params->private_key = private_key->Data(); + params->public_key = public_key->Data().addRef(); + params->private_key = private_key->Data().addRef(); return Just(true); } @@ -528,18 +528,15 @@ bool DHBitsTraits::DeriveBits( Environment* env, const DHBitsConfig& params, ByteSource* out) { - *out = StatelessDiffieHellmanThreadsafe( - params.private_key->GetAsymmetricKey(), - params.public_key->GetAsymmetricKey()); + *out = StatelessDiffieHellmanThreadsafe(params.private_key.GetAsymmetricKey(), + params.public_key.GetAsymmetricKey()); return true; } -Maybe GetDhKeyDetail( - Environment* env, - std::shared_ptr key, - Local target) { - ManagedEVPPKey pkey = key->GetAsymmetricKey(); - CHECK_EQ(EVP_PKEY_id(pkey.get()), EVP_PKEY_DH); +Maybe GetDhKeyDetail(Environment* env, + const KeyObjectData& key, + Local target) { + CHECK_EQ(EVP_PKEY_id(key.GetAsymmetricKey().get()), EVP_PKEY_DH); return Just(true); } diff --git a/src/crypto/crypto_dh.h b/src/crypto/crypto_dh.h index b2df7ca7bb53c0..0f5b835056f901 100644 --- a/src/crypto/crypto_dh.h +++ b/src/crypto/crypto_dh.h @@ -73,18 +73,17 @@ struct DHKeyExportTraits final { unsigned int offset, DHKeyExportConfig* config); - static WebCryptoKeyExportStatus DoExport( - std::shared_ptr key_data, - WebCryptoKeyFormat format, - const DHKeyExportConfig& params, - ByteSource* out); + static WebCryptoKeyExportStatus DoExport(const KeyObjectData& key_data, + WebCryptoKeyFormat format, + const DHKeyExportConfig& params, + ByteSource* out); }; using DHKeyExportJob = KeyExportJob; struct DHBitsConfig final : public MemoryRetainer { - std::shared_ptr private_key; - std::shared_ptr public_key; + KeyObjectData private_key; + KeyObjectData public_key; SET_NO_MEMORY_INFO() SET_MEMORY_INFO_NAME(DHBitsConfig) SET_SELF_SIZE(DHBitsConfig) @@ -116,10 +115,9 @@ struct DHBitsTraits final { using DHBitsJob = DeriveBitsJob; -v8::Maybe GetDhKeyDetail( - Environment* env, - std::shared_ptr key, - v8::Local target); +v8::Maybe GetDhKeyDetail(Environment* env, + const KeyObjectData& key, + v8::Local target); } // namespace crypto } // namespace node diff --git a/src/crypto/crypto_dsa.cc b/src/crypto/crypto_dsa.cc index 57f336dff1d880..eb97e03ea11ce1 100644 --- a/src/crypto/crypto_dsa.cc +++ b/src/crypto/crypto_dsa.cc @@ -103,38 +103,37 @@ Maybe DSAKeyExportTraits::AdditionalConfig( } WebCryptoKeyExportStatus DSAKeyExportTraits::DoExport( - std::shared_ptr key_data, + const KeyObjectData& key_data, WebCryptoKeyFormat format, const DSAKeyExportConfig& params, ByteSource* out) { - CHECK_NE(key_data->GetKeyType(), kKeyTypeSecret); + CHECK_NE(key_data.GetKeyType(), kKeyTypeSecret); switch (format) { case kWebCryptoKeyFormatRaw: // Not supported for RSA keys of either type return WebCryptoKeyExportStatus::FAILED; case kWebCryptoKeyFormatPKCS8: - if (key_data->GetKeyType() != kKeyTypePrivate) + if (key_data.GetKeyType() != kKeyTypePrivate) return WebCryptoKeyExportStatus::INVALID_KEY_TYPE; - return PKEY_PKCS8_Export(key_data.get(), out); + return PKEY_PKCS8_Export(key_data, out); case kWebCryptoKeyFormatSPKI: - if (key_data->GetKeyType() != kKeyTypePublic) + if (key_data.GetKeyType() != kKeyTypePublic) return WebCryptoKeyExportStatus::INVALID_KEY_TYPE; - return PKEY_SPKI_Export(key_data.get(), out); + return PKEY_SPKI_Export(key_data, out); default: UNREACHABLE(); } } -Maybe GetDsaKeyDetail( - Environment* env, - std::shared_ptr key, - Local target) { +Maybe GetDsaKeyDetail(Environment* env, + const KeyObjectData& key, + Local target) { const BIGNUM* p; // Modulus length const BIGNUM* q; // Divisor length - ManagedEVPPKey m_pkey = key->GetAsymmetricKey(); - Mutex::ScopedLock lock(*m_pkey.mutex()); + Mutex::ScopedLock lock(key.mutex()); + const auto& m_pkey = key.GetAsymmetricKey(); int type = EVP_PKEY_id(m_pkey.get()); CHECK(type == EVP_PKEY_DSA); diff --git a/src/crypto/crypto_dsa.h b/src/crypto/crypto_dsa.h index e93cb8075c239b..5e55a5ace31165 100644 --- a/src/crypto/crypto_dsa.h +++ b/src/crypto/crypto_dsa.h @@ -52,19 +52,17 @@ struct DSAKeyExportTraits final { unsigned int offset, DSAKeyExportConfig* config); - static WebCryptoKeyExportStatus DoExport( - std::shared_ptr key_data, - WebCryptoKeyFormat format, - const DSAKeyExportConfig& params, - ByteSource* out); + static WebCryptoKeyExportStatus DoExport(const KeyObjectData& key_data, + WebCryptoKeyFormat format, + const DSAKeyExportConfig& params, + ByteSource* out); }; using DSAKeyExportJob = KeyExportJob; -v8::Maybe GetDsaKeyDetail( - Environment* env, - std::shared_ptr key, - v8::Local target); +v8::Maybe GetDsaKeyDetail(Environment* env, + const KeyObjectData& key, + v8::Local target); namespace DSAAlg { void Initialize(Environment* env, v8::Local target); diff --git a/src/crypto/crypto_ec.cc b/src/crypto/crypto_ec.cc index 4a80f843336a3d..c2c1d961fb14bc 100644 --- a/src/crypto/crypto_ec.cc +++ b/src/crypto/crypto_ec.cc @@ -465,15 +465,15 @@ Maybe ECDHBitsTraits::AdditionalConfig( ASSIGN_OR_RETURN_UNWRAP(&public_key, args[offset + 1], Nothing()); ASSIGN_OR_RETURN_UNWRAP(&private_key, args[offset + 2], Nothing()); - if (private_key->Data()->GetKeyType() != kKeyTypePrivate || - public_key->Data()->GetKeyType() != kKeyTypePublic) { + if (private_key->Data().GetKeyType() != kKeyTypePrivate || + public_key->Data().GetKeyType() != kKeyTypePublic) { THROW_ERR_CRYPTO_INVALID_KEYTYPE(env); return Nothing(); } params->id_ = GetOKPCurveFromName(*name); - params->private_ = private_key->Data(); - params->public_ = public_key->Data(); + params->private_ = private_key->Data().addRef(); + params->public_ = public_key->Data().addRef(); return Just(true); } @@ -482,8 +482,8 @@ bool ECDHBitsTraits::DeriveBits(Environment* env, const ECDHBitsConfig& params, ByteSource* out) { size_t len = 0; - ManagedEVPPKey m_privkey = params.private_->GetAsymmetricKey(); - ManagedEVPPKey m_pubkey = params.public_->GetAsymmetricKey(); + const auto& m_privkey = params.private_.GetAsymmetricKey(); + const auto& m_pubkey = params.public_.GetAsymmetricKey(); switch (params.id_) { case EVP_PKEY_X25519: @@ -493,7 +493,7 @@ bool ECDHBitsTraits::DeriveBits(Environment* env, { ctx.reset(EVP_PKEY_CTX_new(m_privkey.get(), nullptr)); } - Mutex::ScopedLock pub_lock(*m_pubkey.mutex()); + Mutex::ScopedLock pub_lock(params.public_.mutex()); if (EVP_PKEY_derive_init(ctx.get()) <= 0 || EVP_PKEY_derive_set_peer( ctx.get(), @@ -515,11 +515,11 @@ bool ECDHBitsTraits::DeriveBits(Environment* env, default: { const EC_KEY* private_key; { - Mutex::ScopedLock priv_lock(*m_privkey.mutex()); + Mutex::ScopedLock priv_lock(params.private_.mutex()); private_key = EVP_PKEY_get0_EC_KEY(m_privkey.get()); } - Mutex::ScopedLock pub_lock(*m_pubkey.mutex()); + Mutex::ScopedLock pub_lock(params.public_.mutex()); const EC_KEY* public_key = EVP_PKEY_get0_EC_KEY(m_pubkey.get()); const EC_GROUP* group = EC_KEY_get0_group(private_key); @@ -620,13 +620,12 @@ Maybe EcKeyGenTraits::AdditionalConfig( } namespace { -WebCryptoKeyExportStatus EC_Raw_Export( - KeyObjectData* key_data, - const ECKeyExportConfig& params, - ByteSource* out) { - ManagedEVPPKey m_pkey = key_data->GetAsymmetricKey(); +WebCryptoKeyExportStatus EC_Raw_Export(const KeyObjectData& key_data, + const ECKeyExportConfig& params, + ByteSource* out) { + const auto& m_pkey = key_data.GetAsymmetricKey(); CHECK(m_pkey); - Mutex::ScopedLock lock(*m_pkey.mutex()); + Mutex::ScopedLock lock(key_data.mutex()); const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(m_pkey.get()); @@ -635,7 +634,7 @@ WebCryptoKeyExportStatus EC_Raw_Export( if (ec_key == nullptr) { typedef int (*export_fn)(const EVP_PKEY*, unsigned char*, size_t* len); export_fn fn = nullptr; - switch (key_data->GetKeyType()) { + switch (key_data.GetKeyType()) { case kKeyTypePrivate: fn = EVP_PKEY_get_raw_private_key; break; @@ -654,7 +653,7 @@ WebCryptoKeyExportStatus EC_Raw_Export( return WebCryptoKeyExportStatus::INVALID_KEY_TYPE; *out = std::move(data).release(len); } else { - if (key_data->GetKeyType() != kKeyTypePublic) + if (key_data.GetKeyType() != kKeyTypePublic) return WebCryptoKeyExportStatus::INVALID_KEY_TYPE; const EC_GROUP* group = EC_KEY_get0_group(ec_key); const EC_POINT* point = EC_KEY_get0_public_key(ec_key); @@ -686,33 +685,33 @@ Maybe ECKeyExportTraits::AdditionalConfig( } WebCryptoKeyExportStatus ECKeyExportTraits::DoExport( - std::shared_ptr key_data, + const KeyObjectData& key_data, WebCryptoKeyFormat format, const ECKeyExportConfig& params, ByteSource* out) { - CHECK_NE(key_data->GetKeyType(), kKeyTypeSecret); + CHECK_NE(key_data.GetKeyType(), kKeyTypeSecret); switch (format) { case kWebCryptoKeyFormatRaw: - return EC_Raw_Export(key_data.get(), params, out); + return EC_Raw_Export(key_data, params, out); case kWebCryptoKeyFormatPKCS8: - if (key_data->GetKeyType() != kKeyTypePrivate) + if (key_data.GetKeyType() != kKeyTypePrivate) return WebCryptoKeyExportStatus::INVALID_KEY_TYPE; - return PKEY_PKCS8_Export(key_data.get(), out); + return PKEY_PKCS8_Export(key_data, out); case kWebCryptoKeyFormatSPKI: { - if (key_data->GetKeyType() != kKeyTypePublic) + if (key_data.GetKeyType() != kKeyTypePublic) return WebCryptoKeyExportStatus::INVALID_KEY_TYPE; - ManagedEVPPKey m_pkey = key_data->GetAsymmetricKey(); + const auto& m_pkey = key_data.GetAsymmetricKey(); if (EVP_PKEY_id(m_pkey.get()) != EVP_PKEY_EC) { - return PKEY_SPKI_Export(key_data.get(), out); + return PKEY_SPKI_Export(key_data, out); } else { // Ensure exported key is in uncompressed point format. // The temporary EC key is so we can have i2d_PUBKEY_bio() write out // the header but it is a somewhat silly hoop to jump through because // the header is for all practical purposes a static 26 byte sequence // where only the second byte changes. - Mutex::ScopedLock lock(*m_pkey.mutex()); + Mutex::ScopedLock lock(key_data.mutex()); const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(m_pkey.get()); const EC_GROUP* group = EC_KEY_get0_group(ec_key); const EC_POINT* point = EC_KEY_get0_public_key(ec_key); @@ -749,12 +748,11 @@ WebCryptoKeyExportStatus ECKeyExportTraits::DoExport( } } -Maybe ExportJWKEcKey( - Environment* env, - std::shared_ptr key, - Local target) { - ManagedEVPPKey m_pkey = key->GetAsymmetricKey(); - Mutex::ScopedLock lock(*m_pkey.mutex()); +Maybe ExportJWKEcKey(Environment* env, + const KeyObjectData& key, + Local target) { + Mutex::ScopedLock lock(key.mutex()); + const auto& m_pkey = key.GetAsymmetricKey(); CHECK_EQ(EVP_PKEY_id(m_pkey.get()), EVP_PKEY_EC); const EC_KEY* ec = EVP_PKEY_get0_EC_KEY(m_pkey.get()); @@ -826,7 +824,7 @@ Maybe ExportJWKEcKey( return Nothing(); } - if (key->GetKeyType() == kKeyTypePrivate) { + if (key.GetKeyType() == kKeyTypePrivate) { const BIGNUM* pvt = EC_KEY_get0_private_key(ec); return SetEncodedValue(env, target, env->jwk_d_string(), pvt, degree_bytes); } @@ -835,10 +833,10 @@ Maybe ExportJWKEcKey( } Maybe ExportJWKEdKey(Environment* env, - std::shared_ptr key, + const KeyObjectData& key, Local target) { - ManagedEVPPKey pkey = key->GetAsymmetricKey(); - Mutex::ScopedLock lock(*pkey.mutex()); + Mutex::ScopedLock lock(key.mutex()); + const auto& pkey = key.GetAsymmetricKey(); const char* curve = nullptr; switch (EVP_PKEY_id(pkey.get())) { @@ -873,7 +871,7 @@ Maybe ExportJWKEdKey(Environment* env, ByteSource::Builder out(len); - if (key->GetKeyType() == kKeyTypePrivate) { + if (key.GetKeyType() == kKeyTypePrivate) { if (!EVP_PKEY_get_raw_private_key( pkey.get(), out.data(), &len) || !StringBytes::Encode( @@ -907,18 +905,17 @@ Maybe ExportJWKEdKey(Environment* env, return JustVoid(); } -std::shared_ptr ImportJWKEcKey( - Environment* env, - Local jwk, - const FunctionCallbackInfo& args, - unsigned int offset) { +KeyObjectData ImportJWKEcKey(Environment* env, + Local jwk, + const FunctionCallbackInfo& args, + unsigned int offset) { CHECK(args[offset]->IsString()); // curve name Utf8Value curve(env->isolate(), args[offset].As()); int nid = GetCurveFromName(*curve); if (nid == NID_undef) { // Unknown curve THROW_ERR_CRYPTO_INVALID_CURVE(env); - return std::shared_ptr(); + return {}; } Local x_value; @@ -928,14 +925,14 @@ std::shared_ptr ImportJWKEcKey( if (!jwk->Get(env->context(), env->jwk_x_string()).ToLocal(&x_value) || !jwk->Get(env->context(), env->jwk_y_string()).ToLocal(&y_value) || !jwk->Get(env->context(), env->jwk_d_string()).ToLocal(&d_value)) { - return std::shared_ptr(); + return {}; } if (!x_value->IsString() || !y_value->IsString() || (!d_value->IsUndefined() && !d_value->IsString())) { THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK EC key"); - return std::shared_ptr(); + return {}; } KeyType type = d_value->IsString() ? kKeyTypePrivate : kKeyTypePublic; @@ -943,7 +940,7 @@ std::shared_ptr ImportJWKEcKey( ECKeyPointer ec(EC_KEY_new_by_curve_name(nid)); if (!ec) { THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK EC key"); - return std::shared_ptr(); + return {}; } ByteSource x = ByteSource::FromEncodedString(env, x_value.As()); @@ -954,29 +951,28 @@ std::shared_ptr ImportJWKEcKey( x.ToBN().get(), y.ToBN().get())) { THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK EC key"); - return std::shared_ptr(); + return {}; } if (type == kKeyTypePrivate) { ByteSource d = ByteSource::FromEncodedString(env, d_value.As()); if (!EC_KEY_set_private_key(ec.get(), d.ToBN().get())) { THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK EC key"); - return std::shared_ptr(); + return {}; } } EVPKeyPointer pkey(EVP_PKEY_new()); CHECK_EQ(EVP_PKEY_set1_EC_KEY(pkey.get(), ec.get()), 1); - return KeyObjectData::CreateAsymmetric(type, ManagedEVPPKey(std::move(pkey))); + return KeyObjectData::CreateAsymmetric(type, std::move(pkey)); } -Maybe GetEcKeyDetail( - Environment* env, - std::shared_ptr key, - Local target) { - ManagedEVPPKey m_pkey = key->GetAsymmetricKey(); - Mutex::ScopedLock lock(*m_pkey.mutex()); +Maybe GetEcKeyDetail(Environment* env, + const KeyObjectData& key, + Local target) { + Mutex::ScopedLock lock(key.mutex()); + const auto& m_pkey = key.GetAsymmetricKey(); CHECK_EQ(EVP_PKEY_id(m_pkey.get()), EVP_PKEY_EC); const EC_KEY* ec = EVP_PKEY_get0_EC_KEY(m_pkey.get()); @@ -996,7 +992,7 @@ Maybe GetEcKeyDetail( // implementation here is a adapted from Chromium's impl here: // https://github.com/chromium/chromium/blob/7af6cfd/components/webcrypto/algorithms/ecdsa.cc -size_t GroupOrderSize(const ManagedEVPPKey& key) { +size_t GroupOrderSize(const EVPKeyPointer& key) { const EC_KEY* ec = EVP_PKEY_get0_EC_KEY(key.get()); CHECK_NOT_NULL(ec); const EC_GROUP* group = EC_KEY_get0_group(ec); diff --git a/src/crypto/crypto_ec.h b/src/crypto/crypto_ec.h index adeef8e3a3a92d..458bf8892f4d60 100644 --- a/src/crypto/crypto_ec.h +++ b/src/crypto/crypto_ec.h @@ -57,8 +57,8 @@ class ECDH final : public BaseObject { struct ECDHBitsConfig final : public MemoryRetainer { int id_; - std::shared_ptr private_; - std::shared_ptr public_; + KeyObjectData private_; + KeyObjectData public_; void MemoryInfo(MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(ECDHBitsConfig) @@ -134,34 +134,30 @@ struct ECKeyExportTraits final { unsigned int offset, ECKeyExportConfig* config); - static WebCryptoKeyExportStatus DoExport( - std::shared_ptr key_data, - WebCryptoKeyFormat format, - const ECKeyExportConfig& params, - ByteSource* out); + static WebCryptoKeyExportStatus DoExport(const KeyObjectData& key_data, + WebCryptoKeyFormat format, + const ECKeyExportConfig& params, + ByteSource* out); }; using ECKeyExportJob = KeyExportJob; -v8::Maybe ExportJWKEcKey( - Environment* env, - std::shared_ptr key, - v8::Local target); +v8::Maybe ExportJWKEcKey(Environment* env, + const KeyObjectData& key, + v8::Local target); v8::Maybe ExportJWKEdKey(Environment* env, - std::shared_ptr key, + const KeyObjectData& key, v8::Local target); -std::shared_ptr ImportJWKEcKey( - Environment* env, - v8::Local jwk, - const v8::FunctionCallbackInfo& args, - unsigned int offset); +KeyObjectData ImportJWKEcKey(Environment* env, + v8::Local jwk, + const v8::FunctionCallbackInfo& args, + unsigned int offset); -v8::Maybe GetEcKeyDetail( - Environment* env, - std::shared_ptr key, - v8::Local target); +v8::Maybe GetEcKeyDetail(Environment* env, + const KeyObjectData& key, + v8::Local target); } // namespace crypto } // namespace node diff --git a/src/crypto/crypto_hkdf.cc b/src/crypto/crypto_hkdf.cc index aebb5d718dff9e..7f65ee0b713af6 100644 --- a/src/crypto/crypto_hkdf.cc +++ b/src/crypto/crypto_hkdf.cc @@ -21,7 +21,7 @@ HKDFConfig::HKDFConfig(HKDFConfig&& other) noexcept : mode(other.mode), length(other.length), digest(other.digest), - key(other.key), + key(std::move(other.key)), salt(std::move(other.salt)), info(std::move(other.info)) {} @@ -64,7 +64,7 @@ Maybe HKDFTraits::AdditionalConfig( KeyObjectHandle* key; ASSIGN_OR_RETURN_UNWRAP(&key, args[offset + 1], Nothing()); - params->key = key->Data(); + params->key = key->Data().addRef(); ArrayBufferOrViewContents salt(args[offset + 2]); ArrayBufferOrViewContents info(args[offset + 3]); @@ -105,8 +105,8 @@ bool HKDFTraits::DeriveBits( auto dp = ncrypto::hkdf(params.digest, ncrypto::Buffer{ .data = reinterpret_cast( - params.key->GetSymmetricKey()), - .len = params.key->GetSymmetricKeySize(), + params.key.GetSymmetricKey()), + .len = params.key.GetSymmetricKeySize(), }, ncrypto::Buffer{ .data = params.info.data(), diff --git a/src/crypto/crypto_hkdf.h b/src/crypto/crypto_hkdf.h index c4a537cef8a792..40f70c2cf2a447 100644 --- a/src/crypto/crypto_hkdf.h +++ b/src/crypto/crypto_hkdf.h @@ -15,7 +15,7 @@ struct HKDFConfig final : public MemoryRetainer { CryptoJobMode mode; size_t length; const EVP_MD* digest; - std::shared_ptr key; + KeyObjectData key; ByteSource salt; ByteSource info; diff --git a/src/crypto/crypto_hmac.cc b/src/crypto/crypto_hmac.cc index 86315374fdf71c..24e8ce40d5f17a 100644 --- a/src/crypto/crypto_hmac.cc +++ b/src/crypto/crypto_hmac.cc @@ -162,7 +162,7 @@ HmacConfig& HmacConfig::operator=(HmacConfig&& other) noexcept { } void HmacConfig::MemoryInfo(MemoryTracker* tracker) const { - tracker->TrackField("key", key.get()); + tracker->TrackField("key", key); // If the job is sync, then the HmacConfig does not own the data if (job_mode == kCryptoJobAsync) { tracker->TrackFieldWithSize("data", data.size()); @@ -195,7 +195,7 @@ Maybe HmacTraits::AdditionalConfig( KeyObjectHandle* key; ASSIGN_OR_RETURN_UNWRAP(&key, args[offset + 2], Nothing()); - params->key = key->Data(); + params->key = key->Data().addRef(); ArrayBufferOrViewContents data(args[offset + 3]); if (UNLIKELY(!data.CheckSizeInt32())) { @@ -226,13 +226,11 @@ bool HmacTraits::DeriveBits( ByteSource* out) { HMACCtxPointer ctx(HMAC_CTX_new()); - if (!ctx || - !HMAC_Init_ex( - ctx.get(), - params.key->GetSymmetricKey(), - params.key->GetSymmetricKeySize(), - params.digest, - nullptr)) { + if (!ctx || !HMAC_Init_ex(ctx.get(), + params.key.GetSymmetricKey(), + params.key.GetSymmetricKeySize(), + params.digest, + nullptr)) { return false; } diff --git a/src/crypto/crypto_hmac.h b/src/crypto/crypto_hmac.h index c80cc36f11dddc..9057664cc66f08 100644 --- a/src/crypto/crypto_hmac.h +++ b/src/crypto/crypto_hmac.h @@ -42,7 +42,7 @@ class Hmac : public BaseObject { struct HmacConfig final : public MemoryRetainer { CryptoJobMode job_mode; SignConfiguration::Mode mode; - std::shared_ptr key; + KeyObjectData key; ByteSource data; ByteSource signature; const EVP_MD* digest; diff --git a/src/crypto/crypto_keygen.cc b/src/crypto/crypto_keygen.cc index 7e9c3b0dbc07ec..24b99c184759f5 100644 --- a/src/crypto/crypto_keygen.cc +++ b/src/crypto/crypto_keygen.cc @@ -81,8 +81,7 @@ KeyGenJobStatus SecretKeyGenTraits::DoKeyGen(Environment* env, Maybe SecretKeyGenTraits::EncodeKey(Environment* env, SecretKeyGenConfig* params, Local* result) { - std::shared_ptr data = - KeyObjectData::CreateSecret(std::move(params->out)); + auto data = KeyObjectData::CreateSecret(std::move(params->out)); return Just(KeyObjectHandle::Create(env, data).ToLocal(result)); } diff --git a/src/crypto/crypto_keygen.h b/src/crypto/crypto_keygen.h index 389b6b5e8da97d..791ab4adae3fab 100644 --- a/src/crypto/crypto_keygen.h +++ b/src/crypto/crypto_keygen.h @@ -144,16 +144,11 @@ struct KeyPairGenTraits final { return v8::Just(false); } - params->public_key_encoding = ManagedEVPPKey::GetPublicKeyEncodingFromJs( - args, - offset, - kKeyContextGenerate); + params->public_key_encoding = KeyObjectData::GetPublicKeyEncodingFromJs( + args, offset, kKeyContextGenerate); - auto private_key_encoding = - ManagedEVPPKey::GetPrivateKeyEncodingFromJs( - args, - offset, - kKeyContextGenerate); + auto private_key_encoding = KeyObjectData::GetPrivateKeyEncodingFromJs( + args, offset, kKeyContextGenerate); if (!private_key_encoding.IsEmpty()) params->private_key_encoding = private_key_encoding.Release(); @@ -174,7 +169,10 @@ struct KeyPairGenTraits final { if (!EVP_PKEY_keygen(ctx.get(), &pkey)) return KeyGenJobStatus::FAILED; - params->key = ManagedEVPPKey(EVPKeyPointer(pkey)); + auto data = KeyObjectData::CreateAsymmetric(KeyType::kKeyTypePrivate, + EVPKeyPointer(pkey)); + if (UNLIKELY(!data)) return KeyGenJobStatus::FAILED; + params->key = std::move(data); return KeyGenJobStatus::OK; } @@ -231,12 +229,14 @@ template struct KeyPairGenConfig final : public MemoryRetainer { PublicKeyEncodingConfig public_key_encoding; PrivateKeyEncodingConfig private_key_encoding; - ManagedEVPPKey key; + KeyObjectData key; AlgorithmParams params; KeyPairGenConfig() = default; ~KeyPairGenConfig() { - Mutex::ScopedLock priv_lock(*key.mutex()); + if (key) { + Mutex::ScopedLock priv_lock(key.mutex()); + } } explicit KeyPairGenConfig(KeyPairGenConfig&& other) noexcept diff --git a/src/crypto/crypto_keys.cc b/src/crypto/crypto_keys.cc index f49bb1254cb219..ea95d955be2b6d 100644 --- a/src/crypto/crypto_keys.cc +++ b/src/crypto/crypto_keys.cc @@ -431,19 +431,17 @@ MaybeLocal WritePublicKey(Environment* env, } Maybe ExportJWKSecretKey(Environment* env, - std::shared_ptr key, + const KeyObjectData& key, Local target) { - CHECK_EQ(key->GetKeyType(), kKeyTypeSecret); + CHECK_EQ(key.GetKeyType(), kKeyTypeSecret); Local error; Local raw; - MaybeLocal key_data = - StringBytes::Encode( - env->isolate(), - key->GetSymmetricKey(), - key->GetSymmetricKeySize(), - BASE64URL, - &error); + MaybeLocal key_data = StringBytes::Encode(env->isolate(), + key.GetSymmetricKey(), + key.GetSymmetricKeySize(), + BASE64URL, + &error); if (key_data.IsEmpty()) { CHECK(!error.IsEmpty()); env->isolate()->ThrowException(error); @@ -465,26 +463,24 @@ Maybe ExportJWKSecretKey(Environment* env, return JustVoid(); } -std::shared_ptr ImportJWKSecretKey( - Environment* env, - Local jwk) { +KeyObjectData ImportJWKSecretKey(Environment* env, Local jwk) { Local key; if (!jwk->Get(env->context(), env->jwk_k_string()).ToLocal(&key) || !key->IsString()) { THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK secret key format"); - return std::shared_ptr(); + return {}; } static_assert(String::kMaxLength <= INT_MAX); - ByteSource key_data = ByteSource::FromEncodedString(env, key.As()); + auto key_data = ByteSource::FromEncodedString(env, key.As()); return KeyObjectData::CreateSecret(std::move(key_data)); } Maybe ExportJWKAsymmetricKey(Environment* env, - std::shared_ptr key, + const KeyObjectData& key, Local target, bool handleRsaPss) { - switch (EVP_PKEY_id(key->GetAsymmetricKey().get())) { + switch (EVP_PKEY_id(key.GetAsymmetricKey().get())) { case EVP_PKEY_RSA_PSS: { if (handleRsaPss) return ExportJWKRsaKey(env, key, target); break; @@ -504,12 +500,11 @@ Maybe ExportJWKAsymmetricKey(Environment* env, return Nothing(); } -std::shared_ptr ImportJWKAsymmetricKey( - Environment* env, - Local jwk, - std::string_view kty, - const FunctionCallbackInfo& args, - unsigned int offset) { +KeyObjectData ImportJWKAsymmetricKey(Environment* env, + Local jwk, + std::string_view kty, + const FunctionCallbackInfo& args, + unsigned int offset) { if (kty == "RSA") { return ImportJWKRsaKey(env, jwk, args, offset); } else if (kty == "EC") { @@ -518,27 +513,25 @@ std::shared_ptr ImportJWKAsymmetricKey( THROW_ERR_CRYPTO_INVALID_JWK( env, "%s is not a supported JWK key type", kty.data()); - return std::shared_ptr(); + return {}; } -Maybe GetSecretKeyDetail( - Environment* env, - std::shared_ptr key, - Local target) { +Maybe GetSecretKeyDetail(Environment* env, + const KeyObjectData& key, + Local target) { // For the secret key detail, all we care about is the length, // converted to bits. - size_t length = key->GetSymmetricKeySize() * CHAR_BIT; + size_t length = key.GetSymmetricKeySize() * CHAR_BIT; return target->Set(env->context(), env->length_string(), Number::New(env->isolate(), static_cast(length))); } -Maybe GetAsymmetricKeyDetail( - Environment* env, - std::shared_ptr key, - Local target) { - switch (EVP_PKEY_id(key->GetAsymmetricKey().get())) { +Maybe GetAsymmetricKeyDetail(Environment* env, + const KeyObjectData& key, + Local target) { + switch (EVP_PKEY_id(key.GetAsymmetricKey().get())) { case EVP_PKEY_RSA: // Fall through case EVP_PKEY_RSA_PSS: return GetRsaKeyDetail(env, key, target); @@ -551,67 +544,16 @@ Maybe GetAsymmetricKeyDetail( } } // namespace -ManagedEVPPKey::ManagedEVPPKey(EVPKeyPointer&& pkey) : pkey_(std::move(pkey)), - mutex_(std::make_shared()) {} - -ManagedEVPPKey::ManagedEVPPKey(const ManagedEVPPKey& that) { - *this = that; -} - -ManagedEVPPKey& ManagedEVPPKey::operator=(const ManagedEVPPKey& that) { - Mutex::ScopedLock lock(*that.mutex_); - - pkey_.reset(that.get()); - - if (pkey_) - EVP_PKEY_up_ref(pkey_.get()); - - mutex_ = that.mutex_; - - return *this; -} - -ManagedEVPPKey::operator bool() const { - return !!pkey_; -} - -EVP_PKEY* ManagedEVPPKey::get() const { - return pkey_.get(); -} - -Mutex* ManagedEVPPKey::mutex() const { - return mutex_.get(); -} - -void ManagedEVPPKey::MemoryInfo(MemoryTracker* tracker) const { - tracker->TrackFieldWithSize("pkey", - !pkey_ ? 0 : kSizeOf_EVP_PKEY + - size_of_private_key() + - size_of_public_key()); -} - -size_t ManagedEVPPKey::size_of_private_key() const { - size_t len = 0; - return (pkey_ && EVP_PKEY_get_raw_private_key( - pkey_.get(), nullptr, &len) == 1) ? len : 0; -} - -size_t ManagedEVPPKey::size_of_public_key() const { - size_t len = 0; - return (pkey_ && EVP_PKEY_get_raw_public_key( - pkey_.get(), nullptr, &len) == 1) ? len : 0; -} - // This maps true to JustVoid and false to Nothing(). static inline Maybe NothingIfFalse(bool b) { return b ? JustVoid() : Nothing(); } Maybe ExportJWKInner(Environment* env, - std::shared_ptr key, + const KeyObjectData& key, Local result, bool handleRsaPss) { - switch (key->GetKeyType()) { + switch (key.GetKeyType()) { case kKeyTypeSecret: return ExportJWKSecretKey(env, key, result.As()); case kKeyTypePublic: @@ -624,48 +566,48 @@ Maybe ExportJWKInner(Environment* env, } } -Maybe ManagedEVPPKey::ToEncodedPublicKey( +Maybe KeyObjectData::ToEncodedPublicKey( Environment* env, const PublicKeyEncodingConfig& config, Local* out) { - if (!*this) return Nothing(); + CHECK(key_type_ != KeyType::kKeyTypeSecret); if (config.output_key_object_) { // Note that this has the downside of containing sensitive data of the // private key. - std::shared_ptr data = - KeyObjectData::CreateAsymmetric(kKeyTypePublic, *this); - return NothingIfFalse(KeyObjectHandle::Create(env, data).ToLocal(out)); + return NothingIfFalse( + KeyObjectHandle::Create(env, addRefWithType(KeyType::kKeyTypePublic)) + .ToLocal(out)); } else if (config.format_ == kKeyFormatJWK) { - std::shared_ptr data = - KeyObjectData::CreateAsymmetric(kKeyTypePublic, *this); *out = Object::New(env->isolate()); - return ExportJWKInner(env, data, *out, false); + return ExportJWKInner( + env, addRefWithType(KeyType::kKeyTypePublic), *out, false); } - return NothingIfFalse(WritePublicKey(env, get(), config).ToLocal(out)); + return NothingIfFalse( + WritePublicKey(env, GetAsymmetricKey().get(), config).ToLocal(out)); } -Maybe ManagedEVPPKey::ToEncodedPrivateKey( +Maybe KeyObjectData::ToEncodedPrivateKey( Environment* env, const PrivateKeyEncodingConfig& config, Local* out) { - if (!*this) return Nothing(); + CHECK(key_type_ != KeyType::kKeyTypeSecret); if (config.output_key_object_) { - std::shared_ptr data = - KeyObjectData::CreateAsymmetric(kKeyTypePrivate, *this); - return NothingIfFalse(KeyObjectHandle::Create(env, data).ToLocal(out)); + return NothingIfFalse( + KeyObjectHandle::Create(env, addRefWithType(KeyType::kKeyTypePrivate)) + .ToLocal(out)); } else if (config.format_ == kKeyFormatJWK) { - std::shared_ptr data = - KeyObjectData::CreateAsymmetric(kKeyTypePrivate, *this); *out = Object::New(env->isolate()); - return ExportJWKInner(env, data, *out, false); + return ExportJWKInner( + env, addRefWithType(KeyType::kKeyTypePrivate), *out, false); } - return NothingIfFalse(WritePrivateKey(env, get(), config).ToLocal(out)); + return NothingIfFalse( + WritePrivateKey(env, GetAsymmetricKey().get(), config).ToLocal(out)); } NonCopyableMaybe -ManagedEVPPKey::GetPrivateKeyEncodingFromJs( +KeyObjectData::GetPrivateKeyEncodingFromJs( const FunctionCallbackInfo& args, unsigned int* offset, KeyEncodingContext context) { @@ -713,7 +655,7 @@ ManagedEVPPKey::GetPrivateKeyEncodingFromJs( return NonCopyableMaybe(std::move(result)); } -PublicKeyEncodingConfig ManagedEVPPKey::GetPublicKeyEncodingFromJs( +PublicKeyEncodingConfig KeyObjectData::GetPublicKeyEncodingFromJs( const FunctionCallbackInfo& args, unsigned int* offset, KeyEncodingContext context) { @@ -722,8 +664,8 @@ PublicKeyEncodingConfig ManagedEVPPKey::GetPublicKeyEncodingFromJs( return result; } -ManagedEVPPKey ManagedEVPPKey::GetPrivateKeyFromJs( - const FunctionCallbackInfo& args, +KeyObjectData KeyObjectData::GetPrivateKeyFromJs( + const v8::FunctionCallbackInfo& args, unsigned int* offset, bool allow_key_object) { if (args[*offset]->IsString() || IsAnyBufferSource(args[*offset])) { @@ -731,47 +673,50 @@ ManagedEVPPKey ManagedEVPPKey::GetPrivateKeyFromJs( ByteSource key = ByteSource::FromStringOrBuffer(env, args[(*offset)++]); NonCopyableMaybe config = GetPrivateKeyEncodingFromJs(args, offset, kKeyContextInput); - if (config.IsEmpty()) - return ManagedEVPPKey(); + if (config.IsEmpty()) return {}; EVPKeyPointer pkey; ParseKeyResult ret = ParsePrivateKey(&pkey, config.Release(), key.data(), key.size()); - return GetParsedKey(env, std::move(pkey), ret, + return GetParsedKey(KeyType::kKeyTypePrivate, + env, + std::move(pkey), + ret, "Failed to read private key"); } else { CHECK(args[*offset]->IsObject() && allow_key_object); KeyObjectHandle* key; - ASSIGN_OR_RETURN_UNWRAP(&key, args[*offset].As(), ManagedEVPPKey()); - CHECK_EQ(key->Data()->GetKeyType(), kKeyTypePrivate); + ASSIGN_OR_RETURN_UNWRAP(&key, args[*offset].As(), KeyObjectData()); + CHECK_EQ(key->Data().GetKeyType(), kKeyTypePrivate); (*offset) += 4; - return key->Data()->GetAsymmetricKey(); + return key->Data().addRef(); } } -ManagedEVPPKey ManagedEVPPKey::GetPublicOrPrivateKeyFromJs( - const FunctionCallbackInfo& args, - unsigned int* offset) { +KeyObjectData KeyObjectData::GetPublicOrPrivateKeyFromJs( + const FunctionCallbackInfo& args, unsigned int* offset) { if (IsAnyBufferSource(args[*offset])) { Environment* env = Environment::GetCurrent(args); ArrayBufferOrViewContents data(args[(*offset)++]); if (UNLIKELY(!data.CheckSizeInt32())) { THROW_ERR_OUT_OF_RANGE(env, "keyData is too big"); - return ManagedEVPPKey(); + return {}; } NonCopyableMaybe config_ = - GetPrivateKeyEncodingFromJs(args, offset, kKeyContextInput); - if (config_.IsEmpty()) - return ManagedEVPPKey(); + KeyObjectData::GetPrivateKeyEncodingFromJs( + args, offset, kKeyContextInput); + if (config_.IsEmpty()) return {}; ParseKeyResult ret; PrivateKeyEncodingConfig config = config_.Release(); EVPKeyPointer pkey; + KeyType type = KeyType::kKeyTypePublic; if (config.format_ == kKeyFormatPEM) { // For PEM, we can easily determine whether it is a public or private key // by looking for the respective PEM tags. ret = ParsePublicKeyPEM(&pkey, data.data(), data.size()); if (ret == ParseKeyResult::kParseKeyNotRecognized) { + type = KeyType::kKeyTypePrivate; ret = ParsePrivateKey(&pkey, config, data.data(), data.size()); } } else { @@ -797,92 +742,123 @@ ManagedEVPPKey ManagedEVPPKey::GetPublicOrPrivateKeyFromJs( if (is_public) { ret = ParsePublicKey(&pkey, config, data.data(), data.size()); } else { + type = KeyType::kKeyTypePrivate; ret = ParsePrivateKey(&pkey, config, data.data(), data.size()); } } - return ManagedEVPPKey::GetParsedKey( - env, std::move(pkey), ret, "Failed to read asymmetric key"); + return GetParsedKey( + type, env, std::move(pkey), ret, "Failed to read asymmetric key"); } else { CHECK(args[*offset]->IsObject()); KeyObjectHandle* key = Unwrap(args[*offset].As()); CHECK_NOT_NULL(key); - CHECK_NE(key->Data()->GetKeyType(), kKeyTypeSecret); + CHECK_NE(key->Data().GetKeyType(), kKeyTypeSecret); (*offset) += 4; - return key->Data()->GetAsymmetricKey(); + return key->Data().addRef(); } } -ManagedEVPPKey ManagedEVPPKey::GetParsedKey(Environment* env, - EVPKeyPointer&& pkey, - ParseKeyResult ret, - const char* default_msg) { +KeyObjectData KeyObjectData::GetParsedKey(KeyType type, + Environment* env, + EVPKeyPointer&& pkey, + ParseKeyResult ret, + const char* default_msg) { switch (ret) { - case ParseKeyResult::kParseKeyOk: - CHECK(pkey); - break; - case ParseKeyResult::kParseKeyNeedPassphrase: + case ParseKeyResult::kParseKeyOk: { + return CreateAsymmetric(type, std::move(pkey)); + } + case ParseKeyResult::kParseKeyNeedPassphrase: { THROW_ERR_MISSING_PASSPHRASE(env, "Passphrase required for encrypted key"); - break; - default: + return {}; + } + default: { ThrowCryptoError(env, ERR_get_error(), default_msg); + return {}; + } } - - return ManagedEVPPKey(std::move(pkey)); } +KeyObjectData::KeyObjectData(std::nullptr_t) + : key_type_(KeyType::kKeyTypeSecret) {} + KeyObjectData::KeyObjectData(ByteSource symmetric_key) : key_type_(KeyType::kKeyTypeSecret), - symmetric_key_(std::move(symmetric_key)), - asymmetric_key_() {} + data_(std::make_shared(std::move(symmetric_key))) {} -KeyObjectData::KeyObjectData(KeyType type, const ManagedEVPPKey& pkey) - : key_type_(type), symmetric_key_(), asymmetric_key_{pkey} {} +KeyObjectData::KeyObjectData(KeyType type, EVPKeyPointer&& pkey) + : key_type_(type), data_(std::make_shared(std::move(pkey))) {} void KeyObjectData::MemoryInfo(MemoryTracker* tracker) const { + if (!*this) return; switch (GetKeyType()) { - case kKeyTypeSecret: - tracker->TrackFieldWithSize("symmetric_key", symmetric_key_.size()); + case kKeyTypeSecret: { + if (data_->symmetric_key) { + tracker->TrackFieldWithSize("symmetric_key", + data_->symmetric_key.size()); + } break; + } case kKeyTypePrivate: // Fall through - case kKeyTypePublic: - tracker->TrackFieldWithSize("key", asymmetric_key_); + case kKeyTypePublic: { + if (data_->asymmetric_key) { + size_t size = kSizeOf_EVP_PKEY; + size_t len = 0; + if (EVP_PKEY_get_raw_private_key( + data_->asymmetric_key.get(), nullptr, &len) == 1) { + size += len; + } + if (EVP_PKEY_get_raw_public_key( + data_->asymmetric_key.get(), nullptr, &len) == 1) { + size += len; + } + tracker->TrackFieldWithSize("key", size); + } break; + } default: UNREACHABLE(); } } -std::shared_ptr KeyObjectData::CreateSecret(ByteSource key) { - return std::shared_ptr(new KeyObjectData(std::move(key))); +Mutex& KeyObjectData::mutex() const { + if (!mutex_) mutex_ = std::make_shared(); + return *mutex_.get(); +} + +KeyObjectData KeyObjectData::CreateSecret(ByteSource key) { + return KeyObjectData(std::move(key)); } -std::shared_ptr KeyObjectData::CreateAsymmetric( - KeyType key_type, - const ManagedEVPPKey& pkey) { +KeyObjectData KeyObjectData::CreateAsymmetric(KeyType key_type, + EVPKeyPointer&& pkey) { CHECK(pkey); - return std::shared_ptr(new KeyObjectData(key_type, pkey)); + return KeyObjectData(key_type, std::move(pkey)); } KeyType KeyObjectData::GetKeyType() const { + CHECK(data_); return key_type_; } -ManagedEVPPKey KeyObjectData::GetAsymmetricKey() const { +const EVPKeyPointer& KeyObjectData::GetAsymmetricKey() const { CHECK_NE(key_type_, kKeyTypeSecret); - return asymmetric_key_; + CHECK(data_); + return data_->asymmetric_key; } const char* KeyObjectData::GetSymmetricKey() const { CHECK_EQ(key_type_, kKeyTypeSecret); - return symmetric_key_.data(); + CHECK(data_); + return data_->symmetric_key.data(); } size_t KeyObjectData::GetSymmetricKeySize() const { CHECK_EQ(key_type_, kKeyTypeSecret); - return symmetric_key_.size(); + CHECK(data_); + return data_->symmetric_key.size(); } bool KeyObjectHandle::HasInstance(Environment* env, Local value) { @@ -934,9 +910,8 @@ void KeyObjectHandle::RegisterExternalReferences( registry->Register(Equals); } -MaybeLocal KeyObjectHandle::Create( - Environment* env, - std::shared_ptr data) { +MaybeLocal KeyObjectHandle::Create(Environment* env, + const KeyObjectData& data) { Local obj; Local ctor = KeyObjectHandle::Initialize(env); CHECK(!env->crypto_key_object_handle_constructor().IsEmpty()); @@ -945,11 +920,11 @@ MaybeLocal KeyObjectHandle::Create( KeyObjectHandle* key = Unwrap(obj); CHECK_NOT_NULL(key); - key->data_ = data; + key->data_ = data.addRef(); return obj; } -const std::shared_ptr& KeyObjectHandle::Data() { +const KeyObjectData& KeyObjectHandle::Data() { return data_; } @@ -974,7 +949,6 @@ void KeyObjectHandle::Init(const FunctionCallbackInfo& args) { KeyType type = static_cast(args[0].As()->Value()); unsigned int offset; - ManagedEVPPKey pkey; switch (type) { case kKeyTypeSecret: { @@ -987,20 +961,17 @@ void KeyObjectHandle::Init(const FunctionCallbackInfo& args) { CHECK_EQ(args.Length(), 5); offset = 1; - pkey = ManagedEVPPKey::GetPublicOrPrivateKeyFromJs(args, &offset); - if (!pkey) - return; - key->data_ = KeyObjectData::CreateAsymmetric(type, pkey); + auto data = KeyObjectData::GetPublicOrPrivateKeyFromJs(args, &offset); + if (!data) return; + key->data_ = data.addRefWithType(kKeyTypePublic); break; } case kKeyTypePrivate: { CHECK_EQ(args.Length(), 5); - offset = 1; - pkey = ManagedEVPPKey::GetPrivateKeyFromJs(args, &offset, false); - if (!pkey) - return; - key->data_ = KeyObjectData::CreateAsymmetric(type, pkey); + if (auto data = KeyObjectData::GetPrivateKeyFromJs(args, &offset, false)) { + key->data_ = std::move(data); + } break; } default: @@ -1044,7 +1015,7 @@ void KeyObjectHandle::InitJWK(const FunctionCallbackInfo& args) { } } - args.GetReturnValue().Set(key->data_->GetKeyType()); + args.GetReturnValue().Set(key->data_.GetKeyType()); } void KeyObjectHandle::InitECRaw(const FunctionCallbackInfo& args) { @@ -1077,10 +1048,7 @@ void KeyObjectHandle::InitECRaw(const FunctionCallbackInfo& args) { eckey.release(); // Release ownership of the key - key->data_ = - KeyObjectData::CreateAsymmetric( - kKeyTypePublic, - ManagedEVPPKey(std::move(pkey))); + key->data_ = KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(pkey)); args.GetReturnValue().Set(true); } @@ -1113,10 +1081,7 @@ void KeyObjectHandle::InitEDRaw(const FunctionCallbackInfo& args) { EVPKeyPointer pkey(fn(id, nullptr, key_data.data(), key_data.size())); if (!pkey) return args.GetReturnValue().Set(false); - key->data_ = - KeyObjectData::CreateAsymmetric( - type, - ManagedEVPPKey(std::move(pkey))); + key->data_ = KeyObjectData::CreateAsymmetric(type, std::move(pkey)); CHECK(key->data_); break; } @@ -1132,21 +1097,19 @@ void KeyObjectHandle::Equals(const FunctionCallbackInfo& args) { KeyObjectHandle* arg_handle; ASSIGN_OR_RETURN_UNWRAP(&self_handle, args.This()); ASSIGN_OR_RETURN_UNWRAP(&arg_handle, args[0].As()); - std::shared_ptr key = self_handle->Data(); - std::shared_ptr key2 = arg_handle->Data(); + const auto& key = self_handle->Data(); + const auto& key2 = arg_handle->Data(); - KeyType key_type = key->GetKeyType(); - CHECK_EQ(key_type, key2->GetKeyType()); + KeyType key_type = key.GetKeyType(); + CHECK_EQ(key_type, key2.GetKeyType()); bool ret; switch (key_type) { case kKeyTypeSecret: { - size_t size = key->GetSymmetricKeySize(); - if (size == key2->GetSymmetricKeySize()) { + size_t size = key.GetSymmetricKeySize(); + if (size == key2.GetSymmetricKeySize()) { ret = CRYPTO_memcmp( - key->GetSymmetricKey(), - key2->GetSymmetricKey(), - size) == 0; + key.GetSymmetricKey(), key2.GetSymmetricKey(), size) == 0; } else { ret = false; } @@ -1154,8 +1117,8 @@ void KeyObjectHandle::Equals(const FunctionCallbackInfo& args) { } case kKeyTypePublic: case kKeyTypePrivate: { - EVP_PKEY* pkey = key->GetAsymmetricKey().get(); - EVP_PKEY* pkey2 = key2->GetAsymmetricKey().get(); + EVP_PKEY* pkey = key.GetAsymmetricKey().get(); + EVP_PKEY* pkey2 = key2.GetAsymmetricKey().get(); #if OPENSSL_VERSION_MAJOR >= 3 int ok = EVP_PKEY_eq(pkey, pkey2); #else @@ -1182,9 +1145,9 @@ void KeyObjectHandle::GetKeyDetail(const FunctionCallbackInfo& args) { CHECK(args[0]->IsObject()); - std::shared_ptr data = key->Data(); + const auto& data = key->Data(); - switch (data->GetKeyType()) { + switch (data.GetKeyType()) { case kKeyTypeSecret: if (GetSecretKeyDetail(env, data, args[0].As()).IsNothing()) return; @@ -1203,7 +1166,7 @@ void KeyObjectHandle::GetKeyDetail(const FunctionCallbackInfo& args) { } Local KeyObjectHandle::GetAsymmetricKeyType() const { - const ManagedEVPPKey& key = data_->GetAsymmetricKey(); + const auto& key = data_.GetAsymmetricKey(); switch (EVP_PKEY_id(key.get())) { case EVP_PKEY_RSA: return env()->crypto_rsa_string(); @@ -1239,14 +1202,12 @@ void KeyObjectHandle::GetAsymmetricKeyType( bool KeyObjectHandle::CheckEcKeyData() const { MarkPopErrorOnReturn mark_pop_error_on_return; - const ManagedEVPPKey& key = data_->GetAsymmetricKey(); - KeyType type = data_->GetKeyType(); - CHECK_NE(type, kKeyTypeSecret); + const auto& key = data_.GetAsymmetricKey(); EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(key.get(), nullptr)); CHECK(ctx); CHECK_EQ(EVP_PKEY_id(key.get()), EVP_PKEY_EC); - if (type == kKeyTypePrivate) { + if (data_.GetKeyType() == kKeyTypePrivate) { return EVP_PKEY_check(ctx.get()) == 1; } @@ -1269,30 +1230,29 @@ void KeyObjectHandle::GetSymmetricKeySize( KeyObjectHandle* key; ASSIGN_OR_RETURN_UNWRAP(&key, args.This()); args.GetReturnValue().Set( - static_cast(key->Data()->GetSymmetricKeySize())); + static_cast(key->Data().GetSymmetricKeySize())); } void KeyObjectHandle::Export(const FunctionCallbackInfo& args) { KeyObjectHandle* key; ASSIGN_OR_RETURN_UNWRAP(&key, args.This()); - KeyType type = key->Data()->GetKeyType(); + KeyType type = key->Data().GetKeyType(); MaybeLocal result; if (type == kKeyTypeSecret) { result = key->ExportSecretKey(); } else if (type == kKeyTypePublic) { unsigned int offset = 0; - PublicKeyEncodingConfig config = - ManagedEVPPKey::GetPublicKeyEncodingFromJs( - args, &offset, kKeyContextExport); + PublicKeyEncodingConfig config = KeyObjectData::GetPublicKeyEncodingFromJs( + args, &offset, kKeyContextExport); CHECK_EQ(offset, static_cast(args.Length())); result = key->ExportPublicKey(config); } else { CHECK_EQ(type, kKeyTypePrivate); unsigned int offset = 0; NonCopyableMaybe config = - ManagedEVPPKey::GetPrivateKeyEncodingFromJs( + KeyObjectData::GetPrivateKeyEncodingFromJs( args, &offset, kKeyContextExport); if (config.IsEmpty()) return; @@ -1305,19 +1265,19 @@ void KeyObjectHandle::Export(const FunctionCallbackInfo& args) { } MaybeLocal KeyObjectHandle::ExportSecretKey() const { - const char* buf = data_->GetSymmetricKey(); - unsigned int len = data_->GetSymmetricKeySize(); + const char* buf = data_.GetSymmetricKey(); + unsigned int len = data_.GetSymmetricKeySize(); return Buffer::Copy(env(), buf, len).FromMaybe(Local()); } MaybeLocal KeyObjectHandle::ExportPublicKey( const PublicKeyEncodingConfig& config) const { - return WritePublicKey(env(), data_->GetAsymmetricKey().get(), config); + return WritePublicKey(env(), data_.GetAsymmetricKey().get(), config); } MaybeLocal KeyObjectHandle::ExportPrivateKey( const PrivateKeyEncodingConfig& config) const { - return WritePrivateKey(env(), data_->GetAsymmetricKey().get(), config); + return WritePrivateKey(env(), data_.GetAsymmetricKey().get(), config); } void KeyObjectHandle::ExportJWK( @@ -1410,7 +1370,7 @@ BaseObjectPtr NativeKeyObject::KeyObjectTransferData::Deserialize( .IsEmpty()) { return {}; } - switch (data_->GetKeyType()) { + switch (data_.GetKeyType()) { case kKeyTypeSecret: key_ctor = env->crypto_key_object_secret_constructor(); break; @@ -1440,12 +1400,11 @@ std::unique_ptr NativeKeyObject::CloneForMessaging() return std::make_unique(handle_data_); } -WebCryptoKeyExportStatus PKEY_SPKI_Export( - KeyObjectData* key_data, - ByteSource* out) { - CHECK_EQ(key_data->GetKeyType(), kKeyTypePublic); - ManagedEVPPKey m_pkey = key_data->GetAsymmetricKey(); - Mutex::ScopedLock lock(*m_pkey.mutex()); +WebCryptoKeyExportStatus PKEY_SPKI_Export(const KeyObjectData& key_data, + ByteSource* out) { + CHECK_EQ(key_data.GetKeyType(), kKeyTypePublic); + Mutex::ScopedLock lock(key_data.mutex()); + const auto& m_pkey = key_data.GetAsymmetricKey(); auto bio = BIOPointer::NewMem(); CHECK(bio); if (!i2d_PUBKEY_bio(bio.get(), m_pkey.get())) @@ -1455,12 +1414,11 @@ WebCryptoKeyExportStatus PKEY_SPKI_Export( return WebCryptoKeyExportStatus::OK; } -WebCryptoKeyExportStatus PKEY_PKCS8_Export( - KeyObjectData* key_data, - ByteSource* out) { - CHECK_EQ(key_data->GetKeyType(), kKeyTypePrivate); - ManagedEVPPKey m_pkey = key_data->GetAsymmetricKey(); - Mutex::ScopedLock lock(*m_pkey.mutex()); +WebCryptoKeyExportStatus PKEY_PKCS8_Export(const KeyObjectData& key_data, + ByteSource* out) { + CHECK_EQ(key_data.GetKeyType(), kKeyTypePrivate); + Mutex::ScopedLock lock(key_data.mutex()); + const auto& m_pkey = key_data.GetAsymmetricKey(); auto bio = BIOPointer::NewMem(); CHECK(bio); diff --git a/src/crypto/crypto_keys.h b/src/crypto/crypto_keys.h index 11d4e5cdf71e02..808e22e8e16281 100644 --- a/src/crypto/crypto_keys.h +++ b/src/crypto/crypto_keys.h @@ -70,48 +70,48 @@ struct PrivateKeyEncodingConfig : public AsymmetricKeyEncodingConfig { NonCopyableMaybe passphrase_; }; -// This uses the built-in reference counter of OpenSSL to manage an EVP_PKEY -// which is slightly more efficient than using a shared pointer and easier to -// use. -class ManagedEVPPKey : public MemoryRetainer { +// Objects of this class can safely be shared among threads. +class KeyObjectData final : public MemoryRetainer { public: - ManagedEVPPKey() : mutex_(std::make_shared()) {} - explicit ManagedEVPPKey(EVPKeyPointer&& pkey); - ManagedEVPPKey(const ManagedEVPPKey& that); - ManagedEVPPKey& operator=(const ManagedEVPPKey& that); + static KeyObjectData CreateSecret(ByteSource key); + + static KeyObjectData CreateAsymmetric(KeyType type, EVPKeyPointer&& pkey); + + KeyObjectData(std::nullptr_t = nullptr); - operator bool() const; - EVP_PKEY* get() const; - inline const EVPKeyPointer& pkey() const { return pkey_; } - Mutex* mutex() const; + inline operator bool() const { return data_ != nullptr; } + + KeyType GetKeyType() const; + + // These functions allow unprotected access to the raw key material and should + // only be used to implement cryptographic operations requiring the key. + const EVPKeyPointer& GetAsymmetricKey() const; + const char* GetSymmetricKey() const; + size_t GetSymmetricKeySize() const; void MemoryInfo(MemoryTracker* tracker) const override; - SET_MEMORY_INFO_NAME(ManagedEVPPKey) - SET_SELF_SIZE(ManagedEVPPKey) + SET_MEMORY_INFO_NAME(KeyObjectData) + SET_SELF_SIZE(KeyObjectData) + + Mutex& mutex() const; static PublicKeyEncodingConfig GetPublicKeyEncodingFromJs( const v8::FunctionCallbackInfo& args, unsigned int* offset, KeyEncodingContext context); - static NonCopyableMaybe GetPrivateKeyEncodingFromJs( + static KeyObjectData GetPrivateKeyFromJs( const v8::FunctionCallbackInfo& args, unsigned int* offset, - KeyEncodingContext context); - - static ManagedEVPPKey GetParsedKey(Environment* env, - EVPKeyPointer&& pkey, - ParseKeyResult ret, - const char* default_msg); + bool allow_key_object); - static ManagedEVPPKey GetPublicOrPrivateKeyFromJs( - const v8::FunctionCallbackInfo& args, - unsigned int* offset); + static KeyObjectData GetPublicOrPrivateKeyFromJs( + const v8::FunctionCallbackInfo& args, unsigned int* offset); - static ManagedEVPPKey GetPrivateKeyFromJs( + static NonCopyableMaybe GetPrivateKeyEncodingFromJs( const v8::FunctionCallbackInfo& args, unsigned int* offset, - bool allow_key_object); + KeyEncodingContext context); v8::Maybe ToEncodedPublicKey(Environment* env, const PublicKeyEncodingConfig& config, @@ -121,45 +121,41 @@ class ManagedEVPPKey : public MemoryRetainer { const PrivateKeyEncodingConfig& config, v8::Local* out); - private: - size_t size_of_private_key() const; - size_t size_of_public_key() const; - - EVPKeyPointer pkey_; - std::shared_ptr mutex_; -}; - -// Objects of this class can safely be shared among threads. -class KeyObjectData : public MemoryRetainer { - public: - static std::shared_ptr CreateSecret(ByteSource key); - - static std::shared_ptr CreateAsymmetric( - KeyType type, - const ManagedEVPPKey& pkey); - - KeyType GetKeyType() const; - - // These functions allow unprotected access to the raw key material and should - // only be used to implement cryptographic operations requiring the key. - ManagedEVPPKey GetAsymmetricKey() const; - const char* GetSymmetricKey() const; - size_t GetSymmetricKeySize() const; + inline KeyObjectData addRef() const { + return KeyObjectData(key_type_, mutex_, data_); + } - void MemoryInfo(MemoryTracker* tracker) const override; - SET_MEMORY_INFO_NAME(KeyObjectData) - SET_SELF_SIZE(KeyObjectData) + inline KeyObjectData addRefWithType(KeyType type) const { + return KeyObjectData(type, mutex_, data_); + } private: explicit KeyObjectData(ByteSource symmetric_key); + explicit KeyObjectData(KeyType type, EVPKeyPointer&& pkey); + + static KeyObjectData GetParsedKey(KeyType type, + Environment* env, + EVPKeyPointer&& pkey, + ParseKeyResult ret, + const char* default_msg); + + KeyType key_type_; + mutable std::shared_ptr mutex_; + + struct Data { + const ByteSource symmetric_key; + const EVPKeyPointer asymmetric_key; + explicit Data(ByteSource symmetric_key) + : symmetric_key(std::move(symmetric_key)) {} + explicit Data(EVPKeyPointer asymmetric_key) + : asymmetric_key(std::move(asymmetric_key)) {} + }; + std::shared_ptr data_; - KeyObjectData( - KeyType type, - const ManagedEVPPKey& pkey); - - const KeyType key_type_; - const ByteSource symmetric_key_; - const ManagedEVPPKey asymmetric_key_; + KeyObjectData(KeyType type, + std::shared_ptr mutex, + std::shared_ptr data) + : key_type_(type), mutex_(mutex), data_(data) {} }; class KeyObjectHandle : public BaseObject { @@ -169,14 +165,14 @@ class KeyObjectHandle : public BaseObject { static void RegisterExternalReferences(ExternalReferenceRegistry* registry); static v8::MaybeLocal Create(Environment* env, - std::shared_ptr data); + const KeyObjectData& data); // TODO(tniessen): track the memory used by OpenSSL types SET_NO_MEMORY_INFO() SET_MEMORY_INFO_NAME(KeyObjectHandle) SET_SELF_SIZE(KeyObjectHandle) - const std::shared_ptr& Data(); + const KeyObjectData& Data(); protected: static void New(const v8::FunctionCallbackInfo& args); @@ -212,7 +208,7 @@ class KeyObjectHandle : public BaseObject { v8::Local wrap); private: - std::shared_ptr data_; + KeyObjectData data_; }; class NativeKeyObject : public BaseObject { @@ -230,8 +226,8 @@ class NativeKeyObject : public BaseObject { class KeyObjectTransferData : public worker::TransferData { public: - explicit KeyObjectTransferData(const std::shared_ptr& data) - : data_(data) {} + explicit KeyObjectTransferData(const KeyObjectData& data) + : data_(data.addRef()) {} BaseObjectPtr Deserialize( Environment* env, @@ -243,7 +239,7 @@ class NativeKeyObject : public BaseObject { SET_NO_MEMORY_INFO() private: - std::shared_ptr data_; + KeyObjectData data_; }; BaseObject::TransferMode GetTransferMode() const override; @@ -252,13 +248,12 @@ class NativeKeyObject : public BaseObject { private: NativeKeyObject(Environment* env, v8::Local wrap, - const std::shared_ptr& handle_data) - : BaseObject(env, wrap), - handle_data_(handle_data) { + const KeyObjectData& handle_data) + : BaseObject(env, wrap), handle_data_(handle_data.addRef()) { MakeWeak(); } - std::shared_ptr handle_data_; + KeyObjectData handle_data_; }; enum WebCryptoKeyFormat { @@ -323,20 +318,18 @@ class KeyExportJob final : public CryptoJob { CryptoJob::RegisterExternalReferences(New, registry); } - KeyExportJob( - Environment* env, - v8::Local object, - CryptoJobMode mode, - std::shared_ptr key, - WebCryptoKeyFormat format, - AdditionalParams&& params) - : CryptoJob( - env, - object, - AsyncWrap::PROVIDER_KEYEXPORTREQUEST, - mode, - std::move(params)), - key_(key), + KeyExportJob(Environment* env, + v8::Local object, + CryptoJobMode mode, + const KeyObjectData& key, + WebCryptoKeyFormat format, + AdditionalParams&& params) + : CryptoJob(env, + object, + AsyncWrap::PROVIDER_KEYEXPORTREQUEST, + mode, + std::move(params)), + key_(key.addRef()), format_(format) {} WebCryptoKeyFormat format() const { return format_; } @@ -395,18 +388,16 @@ class KeyExportJob final : public CryptoJob { } private: - std::shared_ptr key_; + KeyObjectData key_; WebCryptoKeyFormat format_; ByteSource out_; }; -WebCryptoKeyExportStatus PKEY_SPKI_Export( - KeyObjectData* key_data, - ByteSource* out); +WebCryptoKeyExportStatus PKEY_SPKI_Export(const KeyObjectData& key_data, + ByteSource* out); -WebCryptoKeyExportStatus PKEY_PKCS8_Export( - KeyObjectData* key_data, - ByteSource* out); +WebCryptoKeyExportStatus PKEY_PKCS8_Export(const KeyObjectData& key_data, + ByteSource* out); namespace Keys { void Initialize(Environment* env, v8::Local target); diff --git a/src/crypto/crypto_rsa.cc b/src/crypto/crypto_rsa.cc index 7a9e083de111e9..b52982f27b66cf 100644 --- a/src/crypto/crypto_rsa.cc +++ b/src/crypto/crypto_rsa.cc @@ -187,24 +187,22 @@ Maybe RsaKeyGenTraits::AdditionalConfig( } namespace { -WebCryptoKeyExportStatus RSA_JWK_Export( - KeyObjectData* key_data, - const RSAKeyExportConfig& params, - ByteSource* out) { +WebCryptoKeyExportStatus RSA_JWK_Export(const KeyObjectData& key_data, + const RSAKeyExportConfig& params, + ByteSource* out) { return WebCryptoKeyExportStatus::FAILED; } template -WebCryptoCipherStatus RSA_Cipher( - Environment* env, - KeyObjectData* key_data, - const RSACipherConfig& params, - const ByteSource& in, - ByteSource* out) { - CHECK_NE(key_data->GetKeyType(), kKeyTypeSecret); - ManagedEVPPKey m_pkey = key_data->GetAsymmetricKey(); - Mutex::ScopedLock lock(*m_pkey.mutex()); +WebCryptoCipherStatus RSA_Cipher(Environment* env, + const KeyObjectData& key_data, + const RSACipherConfig& params, + const ByteSource& in, + ByteSource* out) { + CHECK_NE(key_data.GetKeyType(), kKeyTypeSecret); + Mutex::ScopedLock lock(key_data.mutex()); + const auto& m_pkey = key_data.GetAsymmetricKey(); EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(m_pkey.get(), nullptr)); @@ -259,26 +257,26 @@ Maybe RSAKeyExportTraits::AdditionalConfig( } WebCryptoKeyExportStatus RSAKeyExportTraits::DoExport( - std::shared_ptr key_data, + const KeyObjectData& key_data, WebCryptoKeyFormat format, const RSAKeyExportConfig& params, ByteSource* out) { - CHECK_NE(key_data->GetKeyType(), kKeyTypeSecret); + CHECK_NE(key_data.GetKeyType(), kKeyTypeSecret); switch (format) { case kWebCryptoKeyFormatRaw: // Not supported for RSA keys of either type return WebCryptoKeyExportStatus::FAILED; case kWebCryptoKeyFormatJWK: - return RSA_JWK_Export(key_data.get(), params, out); + return RSA_JWK_Export(key_data, params, out); case kWebCryptoKeyFormatPKCS8: - if (key_data->GetKeyType() != kKeyTypePrivate) + if (key_data.GetKeyType() != kKeyTypePrivate) return WebCryptoKeyExportStatus::INVALID_KEY_TYPE; - return PKEY_PKCS8_Export(key_data.get(), out); + return PKEY_PKCS8_Export(key_data, out); case kWebCryptoKeyFormatSPKI: - if (key_data->GetKeyType() != kKeyTypePublic) + if (key_data.GetKeyType() != kKeyTypePublic) return WebCryptoKeyExportStatus::INVALID_KEY_TYPE; - return PKEY_SPKI_Export(key_data.get(), out); + return PKEY_SPKI_Export(key_data, out); default: UNREACHABLE(); } @@ -339,31 +337,30 @@ Maybe RSACipherTraits::AdditionalConfig( return Just(true); } -WebCryptoCipherStatus RSACipherTraits::DoCipher( - Environment* env, - std::shared_ptr key_data, - WebCryptoCipherMode cipher_mode, - const RSACipherConfig& params, - const ByteSource& in, - ByteSource* out) { +WebCryptoCipherStatus RSACipherTraits::DoCipher(Environment* env, + const KeyObjectData& key_data, + WebCryptoCipherMode cipher_mode, + const RSACipherConfig& params, + const ByteSource& in, + ByteSource* out) { switch (cipher_mode) { case kWebCryptoCipherEncrypt: - CHECK_EQ(key_data->GetKeyType(), kKeyTypePublic); + CHECK_EQ(key_data.GetKeyType(), kKeyTypePublic); return RSA_Cipher( - env, key_data.get(), params, in, out); + env, key_data, params, in, out); case kWebCryptoCipherDecrypt: - CHECK_EQ(key_data->GetKeyType(), kKeyTypePrivate); + CHECK_EQ(key_data.GetKeyType(), kKeyTypePrivate); return RSA_Cipher( - env, key_data.get(), params, in, out); + env, key_data, params, in, out); } return WebCryptoCipherStatus::FAILED; } Maybe ExportJWKRsaKey(Environment* env, - std::shared_ptr key, + const KeyObjectData& key, Local target) { - ManagedEVPPKey m_pkey = key->GetAsymmetricKey(); - Mutex::ScopedLock lock(*m_pkey.mutex()); + Mutex::ScopedLock lock(key.mutex()); + const auto& m_pkey = key.GetAsymmetricKey(); int type = EVP_PKEY_id(m_pkey.get()); CHECK(type == EVP_PKEY_RSA || type == EVP_PKEY_RSA_PSS); @@ -399,7 +396,7 @@ Maybe ExportJWKRsaKey(Environment* env, return Nothing(); } - if (key->GetKeyType() == kKeyTypePrivate) { + if (key.GetKeyType() == kKeyTypePrivate) { RSA_get0_factors(rsa, &p, &q); RSA_get0_crt_params(rsa, &dp, &dq, &qi); if (SetEncodedValue(env, target, env->jwk_d_string(), d).IsNothing() || @@ -415,11 +412,10 @@ Maybe ExportJWKRsaKey(Environment* env, return JustVoid(); } -std::shared_ptr ImportJWKRsaKey( - Environment* env, - Local jwk, - const FunctionCallbackInfo& args, - unsigned int offset) { +KeyObjectData ImportJWKRsaKey(Environment* env, + Local jwk, + const FunctionCallbackInfo& args, + unsigned int offset) { Local n_value; Local e_value; Local d_value; @@ -430,12 +426,12 @@ std::shared_ptr ImportJWKRsaKey( !n_value->IsString() || !e_value->IsString()) { THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key"); - return std::shared_ptr(); + return {}; } if (!d_value->IsUndefined() && !d_value->IsString()) { THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key"); - return std::shared_ptr(); + return {}; } KeyType type = d_value->IsString() ? kKeyTypePrivate : kKeyTypePublic; @@ -451,7 +447,7 @@ std::shared_ptr ImportJWKRsaKey( e.ToBN().release(), nullptr)) { THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key"); - return std::shared_ptr(); + return {}; } if (type == kKeyTypePrivate) { @@ -467,7 +463,7 @@ std::shared_ptr ImportJWKRsaKey( !jwk->Get(env->context(), env->jwk_dq_string()).ToLocal(&dq_value) || !jwk->Get(env->context(), env->jwk_qi_string()).ToLocal(&qi_value)) { THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key"); - return std::shared_ptr(); + return {}; } if (!p_value->IsString() || @@ -476,7 +472,7 @@ std::shared_ptr ImportJWKRsaKey( !dq_value->IsString() || !qi_value->IsString()) { THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key"); - return std::shared_ptr(); + return {}; } ByteSource d = ByteSource::FromEncodedString(env, d_value.As()); @@ -494,25 +490,24 @@ std::shared_ptr ImportJWKRsaKey( dq.ToBN().release(), qi.ToBN().release())) { THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key"); - return std::shared_ptr(); + return {}; } } EVPKeyPointer pkey(EVP_PKEY_new()); CHECK_EQ(EVP_PKEY_set1_RSA(pkey.get(), rsa.get()), 1); - return KeyObjectData::CreateAsymmetric(type, ManagedEVPPKey(std::move(pkey))); + return KeyObjectData::CreateAsymmetric(type, std::move(pkey)); } -Maybe GetRsaKeyDetail( - Environment* env, - std::shared_ptr key, - Local target) { +Maybe GetRsaKeyDetail(Environment* env, + const KeyObjectData& key, + Local target) { const BIGNUM* e; // Public Exponent const BIGNUM* n; // Modulus - ManagedEVPPKey m_pkey = key->GetAsymmetricKey(); - Mutex::ScopedLock lock(*m_pkey.mutex()); + Mutex::ScopedLock lock(key.mutex()); + const auto& m_pkey = key.GetAsymmetricKey(); int type = EVP_PKEY_id(m_pkey.get()); CHECK(type == EVP_PKEY_RSA || type == EVP_PKEY_RSA_PSS); diff --git a/src/crypto/crypto_rsa.h b/src/crypto/crypto_rsa.h index e444159daa9404..3f7afbd5c286ab 100644 --- a/src/crypto/crypto_rsa.h +++ b/src/crypto/crypto_rsa.h @@ -68,11 +68,10 @@ struct RSAKeyExportTraits final { unsigned int offset, RSAKeyExportConfig* config); - static WebCryptoKeyExportStatus DoExport( - std::shared_ptr key_data, - WebCryptoKeyFormat format, - const RSAKeyExportConfig& params, - ByteSource* out); + static WebCryptoKeyExportStatus DoExport(const KeyObjectData& key_data, + WebCryptoKeyFormat format, + const RSAKeyExportConfig& params, + ByteSource* out); }; using RSAKeyExportJob = KeyExportJob; @@ -103,31 +102,28 @@ struct RSACipherTraits final { WebCryptoCipherMode cipher_mode, RSACipherConfig* config); - static WebCryptoCipherStatus DoCipher( - Environment* env, - std::shared_ptr key_data, - WebCryptoCipherMode cipher_mode, - const RSACipherConfig& params, - const ByteSource& in, - ByteSource* out); + static WebCryptoCipherStatus DoCipher(Environment* env, + const KeyObjectData& key_data, + WebCryptoCipherMode cipher_mode, + const RSACipherConfig& params, + const ByteSource& in, + ByteSource* out); }; using RSACipherJob = CipherJob; v8::Maybe ExportJWKRsaKey(Environment* env, - std::shared_ptr key, + const KeyObjectData& key, v8::Local target); -std::shared_ptr ImportJWKRsaKey( - Environment* env, - v8::Local jwk, - const v8::FunctionCallbackInfo& args, - unsigned int offset); +KeyObjectData ImportJWKRsaKey(Environment* env, + v8::Local jwk, + const v8::FunctionCallbackInfo& args, + unsigned int offset); -v8::Maybe GetRsaKeyDetail( - Environment* env, - std::shared_ptr key, - v8::Local target); +v8::Maybe GetRsaKeyDetail(Environment* env, + const KeyObjectData& key, + v8::Local target); namespace RSAAlg { void Initialize(Environment* env, v8::Local target); diff --git a/src/crypto/crypto_sig.cc b/src/crypto/crypto_sig.cc index 4566c3e92ca9e0..98e33fcc2c099a 100644 --- a/src/crypto/crypto_sig.cc +++ b/src/crypto/crypto_sig.cc @@ -54,7 +54,7 @@ bool ValidateDSAParameters(EVP_PKEY* key) { return true; } -bool ApplyRSAOptions(const ManagedEVPPKey& pkey, +bool ApplyRSAOptions(const EVPKeyPointer& pkey, EVP_PKEY_CTX* pkctx, int padding, const Maybe& salt_len) { @@ -74,7 +74,7 @@ bool ApplyRSAOptions(const ManagedEVPPKey& pkey, std::unique_ptr Node_SignFinal(Environment* env, EVPMDCtxPointer&& mdctx, - const ManagedEVPPKey& pkey, + const EVPKeyPointer& pkey, int padding, Maybe pss_salt_len) { unsigned char m[EVP_MAX_MD_SIZE]; @@ -117,12 +117,12 @@ std::unique_ptr Node_SignFinal(Environment* env, return nullptr; } -int GetDefaultSignPadding(const ManagedEVPPKey& m_pkey) { +int GetDefaultSignPadding(const EVPKeyPointer& m_pkey) { return EVP_PKEY_id(m_pkey.get()) == EVP_PKEY_RSA_PSS ? RSA_PKCS1_PSS_PADDING : RSA_PKCS1_PADDING; } -unsigned int GetBytesOfRS(const ManagedEVPPKey& pkey) { +unsigned int GetBytesOfRS(const EVPKeyPointer& pkey) { int bits, base_id = EVP_PKEY_base_id(pkey.get()); if (base_id == EVP_PKEY_DSA) { @@ -158,8 +158,10 @@ bool ExtractP1363( } // Returns the maximum size of each of the integers (r, s) of the DSA signature. -std::unique_ptr ConvertSignatureToP1363(Environment* env, - const ManagedEVPPKey& pkey, std::unique_ptr&& signature) { +std::unique_ptr ConvertSignatureToP1363( + Environment* env, + const EVPKeyPointer& pkey, + std::unique_ptr&& signature) { unsigned int n = GetBytesOfRS(pkey); if (n == kNoDsaSignature) return std::move(signature); @@ -178,10 +180,9 @@ std::unique_ptr ConvertSignatureToP1363(Environment* env, } // Returns the maximum size of each of the integers (r, s) of the DSA signature. -ByteSource ConvertSignatureToP1363( - Environment* env, - const ManagedEVPPKey& pkey, - const ByteSource& signature) { +ByteSource ConvertSignatureToP1363(Environment* env, + const EVPKeyPointer& pkey, + const ByteSource& signature) { unsigned int n = GetBytesOfRS(pkey); if (n == kNoDsaSignature) return ByteSource(); @@ -197,9 +198,7 @@ ByteSource ConvertSignatureToP1363( return std::move(out).release(); } -ByteSource ConvertSignatureToDER( - const ManagedEVPPKey& pkey, - ByteSource&& out) { +ByteSource ConvertSignatureToDER(const EVPKeyPointer& pkey, ByteSource&& out) { unsigned int n = GetBytesOfRS(pkey); if (n == kNoDsaSignature) return std::move(out); @@ -272,7 +271,7 @@ void CheckThrow(Environment* env, SignBase::Error error) { } } -bool IsOneShot(const ManagedEVPPKey& key) { +bool IsOneShot(const EVPKeyPointer& key) { switch (EVP_PKEY_id(key.get())) { case EVP_PKEY_ED25519: case EVP_PKEY_ED448: @@ -282,8 +281,7 @@ bool IsOneShot(const ManagedEVPPKey& key) { } } -bool UseP1363Encoding(const ManagedEVPPKey& key, - const DSASigEnc& dsa_encoding) { +bool UseP1363Encoding(const EVPKeyPointer& key, const DSASigEnc& dsa_encoding) { switch (EVP_PKEY_id(key.get())) { case EVP_PKEY_EC: case EVP_PKEY_DSA: @@ -391,11 +389,10 @@ void Sign::SignUpdate(const FunctionCallbackInfo& args) { }); } -Sign::SignResult Sign::SignFinal( - const ManagedEVPPKey& pkey, - int padding, - const Maybe& salt_len, - DSASigEnc dsa_sig_enc) { +Sign::SignResult Sign::SignFinal(const EVPKeyPointer& pkey, + int padding, + const Maybe& salt_len, + DSASigEnc dsa_sig_enc) { if (!mdctx_) return SignResult(kSignNotInitialised); @@ -422,7 +419,9 @@ void Sign::SignFinal(const FunctionCallbackInfo& args) { ClearErrorOnReturn clear_error_on_return; unsigned int offset = 0; - ManagedEVPPKey key = ManagedEVPPKey::GetPrivateKeyFromJs(args, &offset, true); + auto data = KeyObjectData::GetPrivateKeyFromJs(args, &offset, true); + if (UNLIKELY(!data)) return; + const auto& key = data.GetAsymmetricKey(); if (!key) return; @@ -513,7 +512,7 @@ void Verify::VerifyUpdate(const FunctionCallbackInfo& args) { }); } -SignBase::Error Verify::VerifyFinal(const ManagedEVPPKey& pkey, +SignBase::Error Verify::VerifyFinal(const EVPKeyPointer& pkey, const ByteSource& sig, int padding, const Maybe& saltlen, @@ -555,8 +554,9 @@ void Verify::VerifyFinal(const FunctionCallbackInfo& args) { ASSIGN_OR_RETURN_UNWRAP(&verify, args.This()); unsigned int offset = 0; - ManagedEVPPKey pkey = - ManagedEVPPKey::GetPublicOrPrivateKeyFromJs(args, &offset); + auto data = KeyObjectData::GetPublicOrPrivateKeyFromJs(args, &offset); + if (!data) return; + const auto& pkey = data.GetAsymmetricKey(); if (!pkey) return; @@ -642,16 +642,17 @@ Maybe SignTraits::AdditionalConfig( params->mode = static_cast(args[offset].As()->Value()); - ManagedEVPPKey key; unsigned int keyParamOffset = offset + 1; if (params->mode == SignConfiguration::kVerify) { - key = ManagedEVPPKey::GetPublicOrPrivateKeyFromJs(args, &keyParamOffset); + auto data = + KeyObjectData::GetPublicOrPrivateKeyFromJs(args, &keyParamOffset); + if (!data) return Nothing(); + params->key = std::move(data); } else { - key = ManagedEVPPKey::GetPrivateKeyFromJs(args, &keyParamOffset, true); + auto data = KeyObjectData::GetPrivateKeyFromJs(args, &keyParamOffset, true); + if (!data) return Nothing(); + params->key = std::move(data); } - if (!key) - return Nothing(); - params->key = key; ArrayBufferOrViewContents data(args[offset + 5]); if (UNLIKELY(!data.CheckSizeInt32())) { @@ -698,11 +699,10 @@ Maybe SignTraits::AdditionalConfig( } // If this is an EC key (assuming ECDSA) we need to convert the // the signature from WebCrypto format into DER format... - ManagedEVPPKey m_pkey = params->key; - Mutex::ScopedLock lock(*m_pkey.mutex()); - if (UseP1363Encoding(m_pkey, params->dsa_encoding)) { - params->signature = - ConvertSignatureToDER(m_pkey, signature.ToByteSource()); + Mutex::ScopedLock lock(params->key.mutex()); + const auto& akey = params->key.GetAsymmetricKey(); + if (UseP1363Encoding(akey, params->dsa_encoding)) { + params->signature = ConvertSignatureToDER(akey, signature.ToByteSource()); } else { params->signature = mode == kCryptoJobAsync ? signature.ToCopy() @@ -721,25 +721,19 @@ bool SignTraits::DeriveBits( EVPMDCtxPointer context(EVP_MD_CTX_new()); EVP_PKEY_CTX* ctx = nullptr; + const auto& key = params.key.GetAsymmetricKey(); + switch (params.mode) { case SignConfiguration::kSign: if (!EVP_DigestSignInit( - context.get(), - &ctx, - params.digest, - nullptr, - params.key.get())) { + context.get(), &ctx, params.digest, nullptr, key.get())) { crypto::CheckThrow(env, SignBase::Error::kSignInit); return false; } break; case SignConfiguration::kVerify: if (!EVP_DigestVerifyInit( - context.get(), - &ctx, - params.digest, - nullptr, - params.key.get())) { + context.get(), &ctx, params.digest, nullptr, key.get())) { crypto::CheckThrow(env, SignBase::Error::kSignInit); return false; } @@ -747,24 +741,20 @@ bool SignTraits::DeriveBits( } int padding = params.flags & SignConfiguration::kHasPadding - ? params.padding - : GetDefaultSignPadding(params.key); + ? params.padding + : GetDefaultSignPadding(key); Maybe salt_length = params.flags & SignConfiguration::kHasSaltLength ? Just(params.salt_length) : Nothing(); - if (!ApplyRSAOptions( - params.key, - ctx, - padding, - salt_length)) { + if (!ApplyRSAOptions(key, ctx, padding, salt_length)) { crypto::CheckThrow(env, SignBase::Error::kSignPrivateKey); return false; } switch (params.mode) { case SignConfiguration::kSign: { - if (IsOneShot(params.key)) { + if (IsOneShot(key)) { size_t len; if (!EVP_DigestSign( context.get(), @@ -802,9 +792,8 @@ bool SignTraits::DeriveBits( return false; } - if (UseP1363Encoding(params.key, params.dsa_encoding)) { - *out = ConvertSignatureToP1363( - env, params.key, std::move(buf).release()); + if (UseP1363Encoding(key, params.dsa_encoding)) { + *out = ConvertSignatureToP1363(env, key, std::move(buf).release()); } else { *out = std::move(buf).release(len); } diff --git a/src/crypto/crypto_sig.h b/src/crypto/crypto_sig.h index 633201473e4645..f0e0dcf2cf4bae 100644 --- a/src/crypto/crypto_sig.h +++ b/src/crypto/crypto_sig.h @@ -60,11 +60,10 @@ class Sign : public SignBase { : error(err), signature(std::move(sig)) {} }; - SignResult SignFinal( - const ManagedEVPPKey& pkey, - int padding, - const v8::Maybe& saltlen, - DSASigEnc dsa_sig_enc); + SignResult SignFinal(const EVPKeyPointer& pkey, + int padding, + const v8::Maybe& saltlen, + DSASigEnc dsa_sig_enc); static void SignSync(const v8::FunctionCallbackInfo& args); @@ -82,7 +81,7 @@ class Verify : public SignBase { static void Initialize(Environment* env, v8::Local target); static void RegisterExternalReferences(ExternalReferenceRegistry* registry); - Error VerifyFinal(const ManagedEVPPKey& key, + Error VerifyFinal(const EVPKeyPointer& key, const ByteSource& sig, int padding, const v8::Maybe& saltlen, @@ -112,7 +111,7 @@ struct SignConfiguration final : public MemoryRetainer { CryptoJobMode job_mode; Mode mode; - ManagedEVPPKey key; + KeyObjectData key; ByteSource data; ByteSource signature; const EVP_MD* digest = nullptr; diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc index 4660be3cea1449..793c196f8ce538 100644 --- a/src/crypto/crypto_util.cc +++ b/src/crypto/crypto_util.cc @@ -421,8 +421,8 @@ ByteSource ByteSource::FromSymmetricKeyObjectHandle(Local handle) { CHECK(handle->IsObject()); KeyObjectHandle* key = Unwrap(handle.As()); CHECK_NOT_NULL(key); - return Foreign(key->Data()->GetSymmetricKey(), - key->Data()->GetSymmetricKeySize()); + return Foreign(key->Data().GetSymmetricKey(), + key->Data().GetSymmetricKeySize()); } ByteSource ByteSource::Allocated(void* data, size_t size) { diff --git a/src/crypto/crypto_x509.cc b/src/crypto/crypto_x509.cc index 386528e65945f2..af2f953f0388db 100644 --- a/src/crypto/crypto_x509.cc +++ b/src/crypto/crypto_x509.cc @@ -371,11 +371,11 @@ void PublicKey(const FunctionCallbackInfo& args) { ThrowCryptoError(env, result.error.value_or(0)); return; } - std::shared_ptr key_data = KeyObjectData::CreateAsymmetric( - kKeyTypePublic, ManagedEVPPKey(std::move(result.value))); + auto key_data = + KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(result.value)); Local ret; - if (KeyObjectHandle::Create(env, std::move(key_data)).ToLocal(&ret)) { + if (key_data && KeyObjectHandle::Create(env, key_data).ToLocal(&ret)) { args.GetReturnValue().Set(ret); } } @@ -413,9 +413,9 @@ void CheckPrivateKey(const FunctionCallbackInfo& args) { CHECK(args[0]->IsObject()); KeyObjectHandle* key; ASSIGN_OR_RETURN_UNWRAP(&key, args[0]); - CHECK_EQ(key->Data()->GetKeyType(), kKeyTypePrivate); + CHECK_EQ(key->Data().GetKeyType(), kKeyTypePrivate); args.GetReturnValue().Set( - cert->view().checkPrivateKey(key->Data()->GetAsymmetricKey().pkey())); + cert->view().checkPrivateKey(key->Data().GetAsymmetricKey())); } void CheckPublicKey(const FunctionCallbackInfo& args) { @@ -425,10 +425,11 @@ void CheckPublicKey(const FunctionCallbackInfo& args) { CHECK(args[0]->IsObject()); KeyObjectHandle* key; ASSIGN_OR_RETURN_UNWRAP(&key, args[0]); - CHECK_EQ(key->Data()->GetKeyType(), kKeyTypePublic); + // A Public Key can be derived from a private key, so we allow both. + CHECK_NE(key->Data().GetKeyType(), kKeyTypeSecret); args.GetReturnValue().Set( - cert->view().checkPublicKey(key->Data()->GetAsymmetricKey().pkey())); + cert->view().checkPublicKey(key->Data().GetAsymmetricKey())); } void CheckHost(const FunctionCallbackInfo& args) { diff --git a/src/quic/tlscontext.cc b/src/quic/tlscontext.cc index 8441e491d1ca6a..76d11c3d837e2e 100644 --- a/src/quic/tlscontext.cc +++ b/src/quic/tlscontext.cc @@ -92,12 +92,11 @@ bool SetOption(Environment* env, if (!values->Get(context, n).ToLocal(&item)) { return false; } - if constexpr (std::is_same>:: - value) { + if constexpr (std::is_same::value) { if (crypto::KeyObjectHandle::HasInstance(env, item)) { crypto::KeyObjectHandle* handle; ASSIGN_OR_RETURN_UNWRAP(&handle, item, false); - (options->*member).push_back(handle->Data()); + (options->*member).push_back(handle->Data().addRef()); } else { Utf8Value namestr(env->isolate(), name); THROW_ERR_INVALID_ARG_TYPE( @@ -118,12 +117,11 @@ bool SetOption(Environment* env, } } } else { - if constexpr (std::is_same>::value) { + if constexpr (std::is_same::value) { if (crypto::KeyObjectHandle::HasInstance(env, value)) { crypto::KeyObjectHandle* handle; ASSIGN_OR_RETURN_UNWRAP(&handle, value, false); - (options->*member).push_back(handle->Data()); + (options->*member).push_back(handle->Data().addRef()); } else { Utf8Value namestr(env->isolate(), name); THROW_ERR_INVALID_ARG_TYPE( @@ -354,11 +352,11 @@ crypto::SSLCtxPointer TLSContext::Initialize() { { crypto::ClearErrorOnReturn clear_error_on_return; for (const auto& key : options_.keys) { - if (key->GetKeyType() != crypto::KeyType::kKeyTypePrivate) { + if (key.GetKeyType() != crypto::KeyType::kKeyTypePrivate) { validation_error_ = "Invalid key"; return crypto::SSLCtxPointer(); } - if (!SSL_CTX_use_PrivateKey(ctx.get(), key->GetAsymmetricKey().get())) { + if (!SSL_CTX_use_PrivateKey(ctx.get(), key.GetAsymmetricKey().get())) { validation_error_ = "Invalid key"; return crypto::SSLCtxPointer(); } @@ -438,8 +436,7 @@ Maybe TLSContext::Options::From(Environment* env, if (!SET(verify_client) || !SET(enable_tls_trace) || !SET(alpn) || !SET(sni) || !SET(ciphers) || !SET(groups) || !SET(verify_private_key) || - !SET(keylog) || - !SET_VECTOR(std::shared_ptr, keys) || + !SET(keylog) || !SET_VECTOR(crypto::KeyObjectData, keys) || !SET_VECTOR(Store, certs) || !SET_VECTOR(Store, ca) || !SET_VECTOR(Store, crl)) { return Nothing(); diff --git a/src/quic/tlscontext.h b/src/quic/tlscontext.h index d0dfea6106c00e..3ffbd7770443dd 100644 --- a/src/quic/tlscontext.h +++ b/src/quic/tlscontext.h @@ -147,7 +147,7 @@ class TLSContext final : public MemoryRetainer, // The TLS private key(s) to use for this session. // JavaScript option name "keys" - std::vector> keys; + std::vector keys; // Collection of certificates to use for this session. // JavaScript option name "certs"