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"