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<KeyObjectData> ->
          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 <yagiz@nizipli.com>
This commit is contained in:
James M Snell 2024-09-03 17:20:36 -07:00
parent 9087056060
commit 285c6a0df3
29 changed files with 606 additions and 715 deletions

View file

@ -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`

View file

@ -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<const unsigned char*>(key_data->GetSymmetricKey()),
reinterpret_cast<const unsigned char*>(key_data.GetSymmetricKey()),
params.iv.data<unsigned char>(),
encrypt)) {
return WebCryptoCipherStatus::FAILED;
@ -217,13 +214,12 @@ std::vector<unsigned char> 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<const unsigned char*>(key_data->GetSymmetricKey()),
reinterpret_cast<const unsigned char*>(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<bool> AESCipherTraits::AdditionalConfig(
return Just(true);
}
WebCryptoCipherStatus AESCipherTraits::DoCipher(
Environment* env,
std::shared_ptr<KeyObjectData> 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:

View file

@ -67,13 +67,12 @@ struct AESCipherTraits final {
WebCryptoCipherMode cipher_mode,
AESCipherConfig* config);
static WebCryptoCipherStatus DoCipher(
Environment* env,
std::shared_ptr<KeyObjectData> 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<AESCipherTraits>;

View file

@ -989,7 +989,7 @@ template <PublicKeyCipher::Operation operation,
PublicKeyCipher::EVP_PKEY_cipher_t EVP_PKEY_cipher>
bool PublicKeyCipher::Cipher(
Environment* env,
const ManagedEVPPKey& pkey,
const EVPKeyPointer& pkey,
int padding,
const EVP_MD* digest,
const ArrayBufferOrViewContents<unsigned char>& oaep_label,
@ -1056,8 +1056,9 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& 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;

View file

@ -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<unsigned char>& oaep_label,
@ -195,27 +195,23 @@ class CipherJob final : public CryptoJob<CipherTraits> {
CryptoJob<CipherTraits>::RegisterExternalReferences(New, registry);
}
CipherJob(
Environment* env,
v8::Local<v8::Object> object,
CryptoJobMode mode,
KeyObjectHandle* key,
WebCryptoCipherMode cipher_mode,
const ArrayBufferOrViewContents<char>& data,
AdditionalParams&& params)
: CryptoJob<CipherTraits>(
env,
object,
AsyncWrap::PROVIDER_CIPHERREQUEST,
mode,
std::move(params)),
key_(key->Data()),
CipherJob(Environment* env,
v8::Local<v8::Object> object,
CryptoJobMode mode,
KeyObjectHandle* key,
WebCryptoCipherMode cipher_mode,
const ArrayBufferOrViewContents<char>& data,
AdditionalParams&& params)
: CryptoJob<CipherTraits>(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<KeyObjectData> 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<CipherTraits> {
}
private:
std::shared_ptr<KeyObjectData> key_;
KeyObjectData key_;
WebCryptoCipherMode cipher_mode_;
ByteSource in_;
ByteSource out_;

View file

@ -613,15 +613,14 @@ void SecureContext::SetKeylogCallback(KeylogCb cb) {
SSL_CTX_set_keylog_callback(ctx_.get(), cb);
}
Maybe<void> SecureContext::UseKey(Environment* env,
std::shared_ptr<KeyObjectData> key) {
if (key->GetKeyType() != KeyType::kKeyTypePrivate) {
Maybe<void> SecureContext::UseKey(Environment* env, const KeyObjectData& key) {
if (key.GetKeyType() != KeyType::kKeyTypePrivate) {
THROW_ERR_CRYPTO_INVALID_KEYTYPE(env);
return Nothing<void>();
}
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<void>();
}

View file

@ -59,7 +59,7 @@ class SecureContext final : public BaseObject {
v8::Maybe<void> AddCert(Environment* env, BIOPointer&& bio);
v8::Maybe<void> SetCRL(Environment* env, const BIOPointer& bio);
v8::Maybe<void> UseKey(Environment* env, std::shared_ptr<KeyObjectData> key);
v8::Maybe<void> UseKey(Environment* env, const KeyObjectData& key);
void SetCACert(const BIOPointer& bio);
void SetRootCerts();

View file

@ -432,30 +432,30 @@ Maybe<bool> DHKeyExportTraits::AdditionalConfig(
}
WebCryptoKeyExportStatus DHKeyExportTraits::DoExport(
std::shared_ptr<KeyObjectData> 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<Value>& args) {
CHECK(args[0]->IsObject() && args[1]->IsObject());
KeyObjectHandle* our_key_object;
ASSIGN_OR_RETURN_UNWRAP(&our_key_object, args[0].As<Object>());
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<Object>());
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<Value> out;
if (!StatelessDiffieHellmanThreadsafe(our_key, their_key)
@ -503,14 +503,14 @@ Maybe<bool> DHBitsTraits::AdditionalConfig(
ASSIGN_OR_RETURN_UNWRAP(&public_key, args[offset], Nothing<bool>());
ASSIGN_OR_RETURN_UNWRAP(&private_key, args[offset + 1], Nothing<bool>());
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<bool>();
}
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<bool> GetDhKeyDetail(
Environment* env,
std::shared_ptr<KeyObjectData> key,
Local<Object> target) {
ManagedEVPPKey pkey = key->GetAsymmetricKey();
CHECK_EQ(EVP_PKEY_id(pkey.get()), EVP_PKEY_DH);
Maybe<bool> GetDhKeyDetail(Environment* env,
const KeyObjectData& key,
Local<Object> target) {
CHECK_EQ(EVP_PKEY_id(key.GetAsymmetricKey().get()), EVP_PKEY_DH);
return Just(true);
}

View file

@ -73,18 +73,17 @@ struct DHKeyExportTraits final {
unsigned int offset,
DHKeyExportConfig* config);
static WebCryptoKeyExportStatus DoExport(
std::shared_ptr<KeyObjectData> 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<DHKeyExportTraits>;
struct DHBitsConfig final : public MemoryRetainer {
std::shared_ptr<KeyObjectData> private_key;
std::shared_ptr<KeyObjectData> 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<DHBitsTraits>;
v8::Maybe<bool> GetDhKeyDetail(
Environment* env,
std::shared_ptr<KeyObjectData> key,
v8::Local<v8::Object> target);
v8::Maybe<bool> GetDhKeyDetail(Environment* env,
const KeyObjectData& key,
v8::Local<v8::Object> target);
} // namespace crypto
} // namespace node

View file

@ -103,38 +103,37 @@ Maybe<bool> DSAKeyExportTraits::AdditionalConfig(
}
WebCryptoKeyExportStatus DSAKeyExportTraits::DoExport(
std::shared_ptr<KeyObjectData> 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<bool> GetDsaKeyDetail(
Environment* env,
std::shared_ptr<KeyObjectData> key,
Local<Object> target) {
Maybe<bool> GetDsaKeyDetail(Environment* env,
const KeyObjectData& key,
Local<Object> 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);

View file

@ -52,19 +52,17 @@ struct DSAKeyExportTraits final {
unsigned int offset,
DSAKeyExportConfig* config);
static WebCryptoKeyExportStatus DoExport(
std::shared_ptr<KeyObjectData> 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<DSAKeyExportTraits>;
v8::Maybe<bool> GetDsaKeyDetail(
Environment* env,
std::shared_ptr<KeyObjectData> key,
v8::Local<v8::Object> target);
v8::Maybe<bool> GetDsaKeyDetail(Environment* env,
const KeyObjectData& key,
v8::Local<v8::Object> target);
namespace DSAAlg {
void Initialize(Environment* env, v8::Local<v8::Object> target);

View file

@ -465,15 +465,15 @@ Maybe<bool> ECDHBitsTraits::AdditionalConfig(
ASSIGN_OR_RETURN_UNWRAP(&public_key, args[offset + 1], Nothing<bool>());
ASSIGN_OR_RETURN_UNWRAP(&private_key, args[offset + 2], Nothing<bool>());
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<bool>();
}
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<bool> 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<bool> ECKeyExportTraits::AdditionalConfig(
}
WebCryptoKeyExportStatus ECKeyExportTraits::DoExport(
std::shared_ptr<KeyObjectData> 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<void> ExportJWKEcKey(
Environment* env,
std::shared_ptr<KeyObjectData> key,
Local<Object> target) {
ManagedEVPPKey m_pkey = key->GetAsymmetricKey();
Mutex::ScopedLock lock(*m_pkey.mutex());
Maybe<void> ExportJWKEcKey(Environment* env,
const KeyObjectData& key,
Local<Object> 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<void> ExportJWKEcKey(
return Nothing<void>();
}
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<void> ExportJWKEcKey(
}
Maybe<void> ExportJWKEdKey(Environment* env,
std::shared_ptr<KeyObjectData> key,
const KeyObjectData& key,
Local<Object> 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<void> 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<unsigned char>(), &len) ||
!StringBytes::Encode(
@ -907,18 +905,17 @@ Maybe<void> ExportJWKEdKey(Environment* env,
return JustVoid();
}
std::shared_ptr<KeyObjectData> ImportJWKEcKey(
Environment* env,
Local<Object> jwk,
const FunctionCallbackInfo<Value>& args,
unsigned int offset) {
KeyObjectData ImportJWKEcKey(Environment* env,
Local<Object> jwk,
const FunctionCallbackInfo<Value>& args,
unsigned int offset) {
CHECK(args[offset]->IsString()); // curve name
Utf8Value curve(env->isolate(), args[offset].As<String>());
int nid = GetCurveFromName(*curve);
if (nid == NID_undef) { // Unknown curve
THROW_ERR_CRYPTO_INVALID_CURVE(env);
return std::shared_ptr<KeyObjectData>();
return {};
}
Local<Value> x_value;
@ -928,14 +925,14 @@ std::shared_ptr<KeyObjectData> 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<KeyObjectData>();
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<KeyObjectData>();
return {};
}
KeyType type = d_value->IsString() ? kKeyTypePrivate : kKeyTypePublic;
@ -943,7 +940,7 @@ std::shared_ptr<KeyObjectData> 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<KeyObjectData>();
return {};
}
ByteSource x = ByteSource::FromEncodedString(env, x_value.As<String>());
@ -954,29 +951,28 @@ std::shared_ptr<KeyObjectData> ImportJWKEcKey(
x.ToBN().get(),
y.ToBN().get())) {
THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK EC key");
return std::shared_ptr<KeyObjectData>();
return {};
}
if (type == kKeyTypePrivate) {
ByteSource d = ByteSource::FromEncodedString(env, d_value.As<String>());
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<KeyObjectData>();
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<bool> GetEcKeyDetail(
Environment* env,
std::shared_ptr<KeyObjectData> key,
Local<Object> target) {
ManagedEVPPKey m_pkey = key->GetAsymmetricKey();
Mutex::ScopedLock lock(*m_pkey.mutex());
Maybe<bool> GetEcKeyDetail(Environment* env,
const KeyObjectData& key,
Local<Object> 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<bool> 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);

View file

@ -57,8 +57,8 @@ class ECDH final : public BaseObject {
struct ECDHBitsConfig final : public MemoryRetainer {
int id_;
std::shared_ptr<KeyObjectData> private_;
std::shared_ptr<KeyObjectData> 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<KeyObjectData> 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<ECKeyExportTraits>;
v8::Maybe<void> ExportJWKEcKey(
Environment* env,
std::shared_ptr<KeyObjectData> key,
v8::Local<v8::Object> target);
v8::Maybe<void> ExportJWKEdKey(Environment* env,
std::shared_ptr<KeyObjectData> key,
v8::Maybe<void> ExportJWKEcKey(Environment* env,
const KeyObjectData& key,
v8::Local<v8::Object> target);
std::shared_ptr<KeyObjectData> ImportJWKEcKey(
Environment* env,
v8::Local<v8::Object> jwk,
const v8::FunctionCallbackInfo<v8::Value>& args,
unsigned int offset);
v8::Maybe<void> ExportJWKEdKey(Environment* env,
const KeyObjectData& key,
v8::Local<v8::Object> target);
v8::Maybe<bool> GetEcKeyDetail(
Environment* env,
std::shared_ptr<KeyObjectData> key,
v8::Local<v8::Object> target);
KeyObjectData ImportJWKEcKey(Environment* env,
v8::Local<v8::Object> jwk,
const v8::FunctionCallbackInfo<v8::Value>& args,
unsigned int offset);
v8::Maybe<bool> GetEcKeyDetail(Environment* env,
const KeyObjectData& key,
v8::Local<v8::Object> target);
} // namespace crypto
} // namespace node

View file

@ -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<bool> HKDFTraits::AdditionalConfig(
KeyObjectHandle* key;
ASSIGN_OR_RETURN_UNWRAP(&key, args[offset + 1], Nothing<bool>());
params->key = key->Data();
params->key = key->Data().addRef();
ArrayBufferOrViewContents<char> salt(args[offset + 2]);
ArrayBufferOrViewContents<char> info(args[offset + 3]);
@ -105,8 +105,8 @@ bool HKDFTraits::DeriveBits(
auto dp = ncrypto::hkdf(params.digest,
ncrypto::Buffer<const unsigned char>{
.data = reinterpret_cast<const unsigned char*>(
params.key->GetSymmetricKey()),
.len = params.key->GetSymmetricKeySize(),
params.key.GetSymmetricKey()),
.len = params.key.GetSymmetricKeySize(),
},
ncrypto::Buffer<const unsigned char>{
.data = params.info.data<const unsigned char>(),

View file

@ -15,7 +15,7 @@ struct HKDFConfig final : public MemoryRetainer {
CryptoJobMode mode;
size_t length;
const EVP_MD* digest;
std::shared_ptr<KeyObjectData> key;
KeyObjectData key;
ByteSource salt;
ByteSource info;

View file

@ -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<bool> HmacTraits::AdditionalConfig(
KeyObjectHandle* key;
ASSIGN_OR_RETURN_UNWRAP(&key, args[offset + 2], Nothing<bool>());
params->key = key->Data();
params->key = key->Data().addRef();
ArrayBufferOrViewContents<char> 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;
}

View file

@ -42,7 +42,7 @@ class Hmac : public BaseObject {
struct HmacConfig final : public MemoryRetainer {
CryptoJobMode job_mode;
SignConfiguration::Mode mode;
std::shared_ptr<KeyObjectData> key;
KeyObjectData key;
ByteSource data;
ByteSource signature;
const EVP_MD* digest;

View file

@ -81,8 +81,7 @@ KeyGenJobStatus SecretKeyGenTraits::DoKeyGen(Environment* env,
Maybe<bool> SecretKeyGenTraits::EncodeKey(Environment* env,
SecretKeyGenConfig* params,
Local<Value>* result) {
std::shared_ptr<KeyObjectData> data =
KeyObjectData::CreateSecret(std::move(params->out));
auto data = KeyObjectData::CreateSecret(std::move(params->out));
return Just(KeyObjectHandle::Create(env, data).ToLocal(result));
}

View file

@ -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 <typename AlgorithmParams>
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

View file

@ -431,19 +431,17 @@ MaybeLocal<Value> WritePublicKey(Environment* env,
}
Maybe<void> ExportJWKSecretKey(Environment* env,
std::shared_ptr<KeyObjectData> key,
const KeyObjectData& key,
Local<Object> target) {
CHECK_EQ(key->GetKeyType(), kKeyTypeSecret);
CHECK_EQ(key.GetKeyType(), kKeyTypeSecret);
Local<Value> error;
Local<Value> raw;
MaybeLocal<Value> key_data =
StringBytes::Encode(
env->isolate(),
key->GetSymmetricKey(),
key->GetSymmetricKeySize(),
BASE64URL,
&error);
MaybeLocal<Value> 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<void> ExportJWKSecretKey(Environment* env,
return JustVoid();
}
std::shared_ptr<KeyObjectData> ImportJWKSecretKey(
Environment* env,
Local<Object> jwk) {
KeyObjectData ImportJWKSecretKey(Environment* env, Local<Object> jwk) {
Local<Value> 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<KeyObjectData>();
return {};
}
static_assert(String::kMaxLength <= INT_MAX);
ByteSource key_data = ByteSource::FromEncodedString(env, key.As<String>());
auto key_data = ByteSource::FromEncodedString(env, key.As<String>());
return KeyObjectData::CreateSecret(std::move(key_data));
}
Maybe<void> ExportJWKAsymmetricKey(Environment* env,
std::shared_ptr<KeyObjectData> key,
const KeyObjectData& key,
Local<Object> 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<void> ExportJWKAsymmetricKey(Environment* env,
return Nothing<void>();
}
std::shared_ptr<KeyObjectData> ImportJWKAsymmetricKey(
Environment* env,
Local<Object> jwk,
std::string_view kty,
const FunctionCallbackInfo<Value>& args,
unsigned int offset) {
KeyObjectData ImportJWKAsymmetricKey(Environment* env,
Local<Object> jwk,
std::string_view kty,
const FunctionCallbackInfo<Value>& args,
unsigned int offset) {
if (kty == "RSA") {
return ImportJWKRsaKey(env, jwk, args, offset);
} else if (kty == "EC") {
@ -518,27 +513,25 @@ std::shared_ptr<KeyObjectData> ImportJWKAsymmetricKey(
THROW_ERR_CRYPTO_INVALID_JWK(
env, "%s is not a supported JWK key type", kty.data());
return std::shared_ptr<KeyObjectData>();
return {};
}
Maybe<bool> GetSecretKeyDetail(
Environment* env,
std::shared_ptr<KeyObjectData> key,
Local<Object> target) {
Maybe<bool> GetSecretKeyDetail(Environment* env,
const KeyObjectData& key,
Local<Object> 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<double>(length)));
}
Maybe<bool> GetAsymmetricKeyDetail(
Environment* env,
std::shared_ptr<KeyObjectData> key,
Local<Object> target) {
switch (EVP_PKEY_id(key->GetAsymmetricKey().get())) {
Maybe<bool> GetAsymmetricKeyDetail(Environment* env,
const KeyObjectData& key,
Local<Object> 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<bool> GetAsymmetricKeyDetail(
}
} // namespace
ManagedEVPPKey::ManagedEVPPKey(EVPKeyPointer&& pkey) : pkey_(std::move(pkey)),
mutex_(std::make_shared<Mutex>()) {}
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<void>().
static inline Maybe<void> NothingIfFalse(bool b) {
return b ? JustVoid() : Nothing<void>();
}
Maybe<void> ExportJWKInner(Environment* env,
std::shared_ptr<KeyObjectData> key,
const KeyObjectData& key,
Local<Value> result,
bool handleRsaPss) {
switch (key->GetKeyType()) {
switch (key.GetKeyType()) {
case kKeyTypeSecret:
return ExportJWKSecretKey(env, key, result.As<Object>());
case kKeyTypePublic:
@ -624,48 +566,48 @@ Maybe<void> ExportJWKInner(Environment* env,
}
}
Maybe<void> ManagedEVPPKey::ToEncodedPublicKey(
Maybe<void> KeyObjectData::ToEncodedPublicKey(
Environment* env,
const PublicKeyEncodingConfig& config,
Local<Value>* out) {
if (!*this) return Nothing<void>();
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<KeyObjectData> 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<KeyObjectData> 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<void> ManagedEVPPKey::ToEncodedPrivateKey(
Maybe<void> KeyObjectData::ToEncodedPrivateKey(
Environment* env,
const PrivateKeyEncodingConfig& config,
Local<Value>* out) {
if (!*this) return Nothing<void>();
CHECK(key_type_ != KeyType::kKeyTypeSecret);
if (config.output_key_object_) {
std::shared_ptr<KeyObjectData> 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<KeyObjectData> 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<PrivateKeyEncodingConfig>
ManagedEVPPKey::GetPrivateKeyEncodingFromJs(
KeyObjectData::GetPrivateKeyEncodingFromJs(
const FunctionCallbackInfo<Value>& args,
unsigned int* offset,
KeyEncodingContext context) {
@ -713,7 +655,7 @@ ManagedEVPPKey::GetPrivateKeyEncodingFromJs(
return NonCopyableMaybe<PrivateKeyEncodingConfig>(std::move(result));
}
PublicKeyEncodingConfig ManagedEVPPKey::GetPublicKeyEncodingFromJs(
PublicKeyEncodingConfig KeyObjectData::GetPublicKeyEncodingFromJs(
const FunctionCallbackInfo<Value>& args,
unsigned int* offset,
KeyEncodingContext context) {
@ -722,8 +664,8 @@ PublicKeyEncodingConfig ManagedEVPPKey::GetPublicKeyEncodingFromJs(
return result;
}
ManagedEVPPKey ManagedEVPPKey::GetPrivateKeyFromJs(
const FunctionCallbackInfo<Value>& args,
KeyObjectData KeyObjectData::GetPrivateKeyFromJs(
const v8::FunctionCallbackInfo<v8::Value>& 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<PrivateKeyEncodingConfig> config =
GetPrivateKeyEncodingFromJs(args, offset, kKeyContextInput);
if (config.IsEmpty())
return ManagedEVPPKey();
if (config.IsEmpty()) return {};
EVPKeyPointer pkey;
ParseKeyResult ret =
ParsePrivateKey(&pkey, config.Release(), key.data<char>(), 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<Object>(), ManagedEVPPKey());
CHECK_EQ(key->Data()->GetKeyType(), kKeyTypePrivate);
ASSIGN_OR_RETURN_UNWRAP(&key, args[*offset].As<Object>(), KeyObjectData());
CHECK_EQ(key->Data().GetKeyType(), kKeyTypePrivate);
(*offset) += 4;
return key->Data()->GetAsymmetricKey();
return key->Data().addRef();
}
}
ManagedEVPPKey ManagedEVPPKey::GetPublicOrPrivateKeyFromJs(
const FunctionCallbackInfo<Value>& args,
unsigned int* offset) {
KeyObjectData KeyObjectData::GetPublicOrPrivateKeyFromJs(
const FunctionCallbackInfo<Value>& args, unsigned int* offset) {
if (IsAnyBufferSource(args[*offset])) {
Environment* env = Environment::GetCurrent(args);
ArrayBufferOrViewContents<char> data(args[(*offset)++]);
if (UNLIKELY(!data.CheckSizeInt32())) {
THROW_ERR_OUT_OF_RANGE(env, "keyData is too big");
return ManagedEVPPKey();
return {};
}
NonCopyableMaybe<PrivateKeyEncodingConfig> 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,93 +742,124 @@ 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 =
BaseObject::Unwrap<KeyObjectHandle>(args[*offset].As<Object>());
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<Data>(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<Data>(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> KeyObjectData::CreateSecret(ByteSource key) {
return std::shared_ptr<KeyObjectData>(new KeyObjectData(std::move(key)));
Mutex& KeyObjectData::mutex() const {
if (!mutex_) mutex_ = std::make_shared<Mutex>();
return *mutex_.get();
}
std::shared_ptr<KeyObjectData> KeyObjectData::CreateAsymmetric(
KeyType key_type,
const ManagedEVPPKey& pkey) {
KeyObjectData KeyObjectData::CreateSecret(ByteSource key) {
return KeyObjectData(std::move(key));
}
KeyObjectData KeyObjectData::CreateAsymmetric(KeyType key_type,
EVPKeyPointer&& pkey) {
CHECK(pkey);
return std::shared_ptr<KeyObjectData>(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<char>();
CHECK(data_);
return data_->symmetric_key.data<char>();
}
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> value) {
@ -935,9 +911,8 @@ void KeyObjectHandle::RegisterExternalReferences(
registry->Register(Equals);
}
MaybeLocal<Object> KeyObjectHandle::Create(
Environment* env,
std::shared_ptr<KeyObjectData> data) {
MaybeLocal<Object> KeyObjectHandle::Create(Environment* env,
const KeyObjectData& data) {
Local<Object> obj;
Local<Function> ctor = KeyObjectHandle::Initialize(env);
CHECK(!env->crypto_key_object_handle_constructor().IsEmpty());
@ -946,11 +921,11 @@ MaybeLocal<Object> KeyObjectHandle::Create(
KeyObjectHandle* key = Unwrap<KeyObjectHandle>(obj);
CHECK_NOT_NULL(key);
key->data_ = data;
key->data_ = data.addRef();
return obj;
}
const std::shared_ptr<KeyObjectData>& KeyObjectHandle::Data() {
const KeyObjectData& KeyObjectHandle::Data() {
return data_;
}
@ -975,7 +950,6 @@ void KeyObjectHandle::Init(const FunctionCallbackInfo<Value>& args) {
KeyType type = static_cast<KeyType>(args[0].As<Uint32>()->Value());
unsigned int offset;
ManagedEVPPKey pkey;
switch (type) {
case kKeyTypeSecret: {
@ -988,20 +962,17 @@ void KeyObjectHandle::Init(const FunctionCallbackInfo<Value>& 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:
@ -1045,7 +1016,7 @@ void KeyObjectHandle::InitJWK(const FunctionCallbackInfo<Value>& args) {
}
}
args.GetReturnValue().Set(key->data_->GetKeyType());
args.GetReturnValue().Set(key->data_.GetKeyType());
}
void KeyObjectHandle::InitECRaw(const FunctionCallbackInfo<Value>& args) {
@ -1078,10 +1049,7 @@ void KeyObjectHandle::InitECRaw(const FunctionCallbackInfo<Value>& 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);
}
@ -1114,10 +1082,7 @@ void KeyObjectHandle::InitEDRaw(const FunctionCallbackInfo<Value>& 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;
}
@ -1133,21 +1098,19 @@ void KeyObjectHandle::Equals(const FunctionCallbackInfo<Value>& args) {
KeyObjectHandle* arg_handle;
ASSIGN_OR_RETURN_UNWRAP(&self_handle, args.This());
ASSIGN_OR_RETURN_UNWRAP(&arg_handle, args[0].As<Object>());
std::shared_ptr<KeyObjectData> key = self_handle->Data();
std::shared_ptr<KeyObjectData> 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;
}
@ -1155,8 +1118,8 @@ void KeyObjectHandle::Equals(const FunctionCallbackInfo<Value>& 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
@ -1183,9 +1146,9 @@ void KeyObjectHandle::GetKeyDetail(const FunctionCallbackInfo<Value>& args) {
CHECK(args[0]->IsObject());
std::shared_ptr<KeyObjectData> data = key->Data();
const auto& data = key->Data();
switch (data->GetKeyType()) {
switch (data.GetKeyType()) {
case kKeyTypeSecret:
if (GetSecretKeyDetail(env, data, args[0].As<Object>()).IsNothing())
return;
@ -1204,7 +1167,7 @@ void KeyObjectHandle::GetKeyDetail(const FunctionCallbackInfo<Value>& args) {
}
Local<Value> 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();
@ -1240,14 +1203,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;
}
@ -1270,30 +1231,29 @@ void KeyObjectHandle::GetSymmetricKeySize(
KeyObjectHandle* key;
ASSIGN_OR_RETURN_UNWRAP(&key, args.This());
args.GetReturnValue().Set(
static_cast<uint32_t>(key->Data()->GetSymmetricKeySize()));
static_cast<uint32_t>(key->Data().GetSymmetricKeySize()));
}
void KeyObjectHandle::Export(const FunctionCallbackInfo<Value>& args) {
KeyObjectHandle* key;
ASSIGN_OR_RETURN_UNWRAP(&key, args.This());
KeyType type = key->Data()->GetKeyType();
KeyType type = key->Data().GetKeyType();
MaybeLocal<Value> 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<unsigned int>(args.Length()));
result = key->ExportPublicKey(config);
} else {
CHECK_EQ(type, kKeyTypePrivate);
unsigned int offset = 0;
NonCopyableMaybe<PrivateKeyEncodingConfig> config =
ManagedEVPPKey::GetPrivateKeyEncodingFromJs(
KeyObjectData::GetPrivateKeyEncodingFromJs(
args, &offset, kKeyContextExport);
if (config.IsEmpty())
return;
@ -1306,19 +1266,19 @@ void KeyObjectHandle::Export(const FunctionCallbackInfo<Value>& args) {
}
MaybeLocal<Value> 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<Value>());
}
MaybeLocal<Value> KeyObjectHandle::ExportPublicKey(
const PublicKeyEncodingConfig& config) const {
return WritePublicKey(env(), data_->GetAsymmetricKey().get(), config);
return WritePublicKey(env(), data_.GetAsymmetricKey().get(), config);
}
MaybeLocal<Value> KeyObjectHandle::ExportPrivateKey(
const PrivateKeyEncodingConfig& config) const {
return WritePrivateKey(env(), data_->GetAsymmetricKey().get(), config);
return WritePrivateKey(env(), data_.GetAsymmetricKey().get(), config);
}
void KeyObjectHandle::ExportJWK(
@ -1411,7 +1371,7 @@ BaseObjectPtr<BaseObject> NativeKeyObject::KeyObjectTransferData::Deserialize(
.IsEmpty()) {
return {};
}
switch (data_->GetKeyType()) {
switch (data_.GetKeyType()) {
case kKeyTypeSecret:
key_ctor = env->crypto_key_object_secret_constructor();
break;
@ -1441,12 +1401,11 @@ std::unique_ptr<worker::TransferData> NativeKeyObject::CloneForMessaging()
return std::make_unique<KeyObjectTransferData>(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()))
@ -1456,12 +1415,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);

View file

@ -70,49 +70,49 @@ struct PrivateKeyEncodingConfig : public AsymmetricKeyEncodingConfig {
NonCopyableMaybe<ByteSource> 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<Mutex>()) {}
explicit ManagedEVPPKey(EVPKeyPointer&& pkey);
ManagedEVPPKey(const ManagedEVPPKey& that);
ManagedEVPPKey& operator=(const ManagedEVPPKey& that);
static KeyObjectData CreateSecret(ByteSource key);
operator bool() const;
EVP_PKEY* get() const;
inline const EVPKeyPointer& pkey() const { return pkey_; }
Mutex* mutex() const;
static KeyObjectData CreateAsymmetric(KeyType type, EVPKeyPointer&& pkey);
KeyObjectData(std::nullptr_t = nullptr);
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<v8::Value>& args,
unsigned int* offset,
KeyEncodingContext context);
static KeyObjectData GetPrivateKeyFromJs(
const v8::FunctionCallbackInfo<v8::Value>& args,
unsigned int* offset,
bool allow_key_object);
static KeyObjectData GetPublicOrPrivateKeyFromJs(
const v8::FunctionCallbackInfo<v8::Value>& args, unsigned int* offset);
static NonCopyableMaybe<PrivateKeyEncodingConfig> GetPrivateKeyEncodingFromJs(
const v8::FunctionCallbackInfo<v8::Value>& args,
unsigned int* offset,
KeyEncodingContext context);
static ManagedEVPPKey GetParsedKey(Environment* env,
EVPKeyPointer&& pkey,
ParseKeyResult ret,
const char* default_msg);
static ManagedEVPPKey GetPublicOrPrivateKeyFromJs(
const v8::FunctionCallbackInfo<v8::Value>& args,
unsigned int* offset);
static ManagedEVPPKey GetPrivateKeyFromJs(
const v8::FunctionCallbackInfo<v8::Value>& args,
unsigned int* offset,
bool allow_key_object);
v8::Maybe<void> ToEncodedPublicKey(Environment* env,
const PublicKeyEncodingConfig& config,
v8::Local<v8::Value>* out);
@ -121,45 +121,41 @@ class ManagedEVPPKey : public MemoryRetainer {
const PrivateKeyEncodingConfig& config,
v8::Local<v8::Value>* out);
private:
size_t size_of_private_key() const;
size_t size_of_public_key() const;
inline KeyObjectData addRef() const {
return KeyObjectData(key_type_, mutex_, data_);
}
EVPKeyPointer pkey_;
std::shared_ptr<Mutex> mutex_;
};
// Objects of this class can safely be shared among threads.
class KeyObjectData : public MemoryRetainer {
public:
static std::shared_ptr<KeyObjectData> CreateSecret(ByteSource key);
static std::shared_ptr<KeyObjectData> 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;
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);
KeyObjectData(
KeyType type,
const ManagedEVPPKey& pkey);
static KeyObjectData GetParsedKey(KeyType type,
Environment* env,
EVPKeyPointer&& pkey,
ParseKeyResult ret,
const char* default_msg);
const KeyType key_type_;
const ByteSource symmetric_key_;
const ManagedEVPPKey asymmetric_key_;
KeyType key_type_;
mutable std::shared_ptr<Mutex> 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> data_;
KeyObjectData(KeyType type,
std::shared_ptr<Mutex> mutex,
std::shared_ptr<Data> 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<v8::Object> Create(Environment* env,
std::shared_ptr<KeyObjectData> 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<KeyObjectData>& Data();
const KeyObjectData& Data();
protected:
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
@ -212,7 +208,7 @@ class KeyObjectHandle : public BaseObject {
v8::Local<v8::Object> wrap);
private:
std::shared_ptr<KeyObjectData> 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<KeyObjectData>& data)
: data_(data) {}
explicit KeyObjectTransferData(const KeyObjectData& data)
: data_(data.addRef()) {}
BaseObjectPtr<BaseObject> Deserialize(
Environment* env,
@ -243,7 +239,7 @@ class NativeKeyObject : public BaseObject {
SET_NO_MEMORY_INFO()
private:
std::shared_ptr<KeyObjectData> data_;
KeyObjectData data_;
};
BaseObject::TransferMode GetTransferMode() const override;
@ -252,13 +248,12 @@ class NativeKeyObject : public BaseObject {
private:
NativeKeyObject(Environment* env,
v8::Local<v8::Object> wrap,
const std::shared_ptr<KeyObjectData>& 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<KeyObjectData> handle_data_;
KeyObjectData handle_data_;
};
enum WebCryptoKeyFormat {
@ -323,20 +318,18 @@ class KeyExportJob final : public CryptoJob<KeyExportTraits> {
CryptoJob<KeyExportTraits>::RegisterExternalReferences(New, registry);
}
KeyExportJob(
Environment* env,
v8::Local<v8::Object> object,
CryptoJobMode mode,
std::shared_ptr<KeyObjectData> key,
WebCryptoKeyFormat format,
AdditionalParams&& params)
: CryptoJob<KeyExportTraits>(
env,
object,
AsyncWrap::PROVIDER_KEYEXPORTREQUEST,
mode,
std::move(params)),
key_(key),
KeyExportJob(Environment* env,
v8::Local<v8::Object> object,
CryptoJobMode mode,
const KeyObjectData& key,
WebCryptoKeyFormat format,
AdditionalParams&& params)
: CryptoJob<KeyExportTraits>(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<KeyExportTraits> {
}
private:
std::shared_ptr<KeyObjectData> 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<v8::Object> target);

View file

@ -187,24 +187,22 @@ Maybe<bool> 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 <PublicKeyCipher::EVP_PKEY_cipher_init_t init,
PublicKeyCipher::EVP_PKEY_cipher_t cipher>
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<bool> RSAKeyExportTraits::AdditionalConfig(
}
WebCryptoKeyExportStatus RSAKeyExportTraits::DoExport(
std::shared_ptr<KeyObjectData> 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<bool> RSACipherTraits::AdditionalConfig(
return Just(true);
}
WebCryptoCipherStatus RSACipherTraits::DoCipher(
Environment* env,
std::shared_ptr<KeyObjectData> 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<EVP_PKEY_encrypt_init, EVP_PKEY_encrypt>(
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<EVP_PKEY_decrypt_init, EVP_PKEY_decrypt>(
env, key_data.get(), params, in, out);
env, key_data, params, in, out);
}
return WebCryptoCipherStatus::FAILED;
}
Maybe<void> ExportJWKRsaKey(Environment* env,
std::shared_ptr<KeyObjectData> key,
const KeyObjectData& key,
Local<Object> 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<void> ExportJWKRsaKey(Environment* env,
return Nothing<void>();
}
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<void> ExportJWKRsaKey(Environment* env,
return JustVoid();
}
std::shared_ptr<KeyObjectData> ImportJWKRsaKey(
Environment* env,
Local<Object> jwk,
const FunctionCallbackInfo<Value>& args,
unsigned int offset) {
KeyObjectData ImportJWKRsaKey(Environment* env,
Local<Object> jwk,
const FunctionCallbackInfo<Value>& args,
unsigned int offset) {
Local<Value> n_value;
Local<Value> e_value;
Local<Value> d_value;
@ -430,12 +426,12 @@ std::shared_ptr<KeyObjectData> ImportJWKRsaKey(
!n_value->IsString() ||
!e_value->IsString()) {
THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
return std::shared_ptr<KeyObjectData>();
return {};
}
if (!d_value->IsUndefined() && !d_value->IsString()) {
THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
return std::shared_ptr<KeyObjectData>();
return {};
}
KeyType type = d_value->IsString() ? kKeyTypePrivate : kKeyTypePublic;
@ -451,7 +447,7 @@ std::shared_ptr<KeyObjectData> ImportJWKRsaKey(
e.ToBN().release(),
nullptr)) {
THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
return std::shared_ptr<KeyObjectData>();
return {};
}
if (type == kKeyTypePrivate) {
@ -467,7 +463,7 @@ std::shared_ptr<KeyObjectData> 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<KeyObjectData>();
return {};
}
if (!p_value->IsString() ||
@ -476,7 +472,7 @@ std::shared_ptr<KeyObjectData> ImportJWKRsaKey(
!dq_value->IsString() ||
!qi_value->IsString()) {
THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
return std::shared_ptr<KeyObjectData>();
return {};
}
ByteSource d = ByteSource::FromEncodedString(env, d_value.As<String>());
@ -494,25 +490,24 @@ std::shared_ptr<KeyObjectData> ImportJWKRsaKey(
dq.ToBN().release(),
qi.ToBN().release())) {
THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
return std::shared_ptr<KeyObjectData>();
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<bool> GetRsaKeyDetail(
Environment* env,
std::shared_ptr<KeyObjectData> key,
Local<Object> target) {
Maybe<bool> GetRsaKeyDetail(Environment* env,
const KeyObjectData& key,
Local<Object> 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);

View file

@ -68,11 +68,10 @@ struct RSAKeyExportTraits final {
unsigned int offset,
RSAKeyExportConfig* config);
static WebCryptoKeyExportStatus DoExport(
std::shared_ptr<KeyObjectData> 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<RSAKeyExportTraits>;
@ -103,31 +102,28 @@ struct RSACipherTraits final {
WebCryptoCipherMode cipher_mode,
RSACipherConfig* config);
static WebCryptoCipherStatus DoCipher(
Environment* env,
std::shared_ptr<KeyObjectData> 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<RSACipherTraits>;
v8::Maybe<void> ExportJWKRsaKey(Environment* env,
std::shared_ptr<KeyObjectData> key,
const KeyObjectData& key,
v8::Local<v8::Object> target);
std::shared_ptr<KeyObjectData> ImportJWKRsaKey(
Environment* env,
v8::Local<v8::Object> jwk,
const v8::FunctionCallbackInfo<v8::Value>& args,
unsigned int offset);
KeyObjectData ImportJWKRsaKey(Environment* env,
v8::Local<v8::Object> jwk,
const v8::FunctionCallbackInfo<v8::Value>& args,
unsigned int offset);
v8::Maybe<bool> GetRsaKeyDetail(
Environment* env,
std::shared_ptr<KeyObjectData> key,
v8::Local<v8::Object> target);
v8::Maybe<bool> GetRsaKeyDetail(Environment* env,
const KeyObjectData& key,
v8::Local<v8::Object> target);
namespace RSAAlg {
void Initialize(Environment* env, v8::Local<v8::Object> target);

View file

@ -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<int>& salt_len) {
@ -74,7 +74,7 @@ bool ApplyRSAOptions(const ManagedEVPPKey& pkey,
std::unique_ptr<BackingStore> Node_SignFinal(Environment* env,
EVPMDCtxPointer&& mdctx,
const ManagedEVPPKey& pkey,
const EVPKeyPointer& pkey,
int padding,
Maybe<int> pss_salt_len) {
unsigned char m[EVP_MAX_MD_SIZE];
@ -117,12 +117,12 @@ std::unique_ptr<BackingStore> 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<BackingStore> ConvertSignatureToP1363(Environment* env,
const ManagedEVPPKey& pkey, std::unique_ptr<BackingStore>&& signature) {
std::unique_ptr<BackingStore> ConvertSignatureToP1363(
Environment* env,
const EVPKeyPointer& pkey,
std::unique_ptr<BackingStore>&& signature) {
unsigned int n = GetBytesOfRS(pkey);
if (n == kNoDsaSignature)
return std::move(signature);
@ -178,10 +180,9 @@ std::unique_ptr<BackingStore> 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<Value>& args) {
});
}
Sign::SignResult Sign::SignFinal(
const ManagedEVPPKey& pkey,
int padding,
const Maybe<int>& salt_len,
DSASigEnc dsa_sig_enc) {
Sign::SignResult Sign::SignFinal(const EVPKeyPointer& pkey,
int padding,
const Maybe<int>& salt_len,
DSASigEnc dsa_sig_enc) {
if (!mdctx_)
return SignResult(kSignNotInitialised);
@ -422,7 +419,9 @@ void Sign::SignFinal(const FunctionCallbackInfo<Value>& 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<Value>& args) {
});
}
SignBase::Error Verify::VerifyFinal(const ManagedEVPPKey& pkey,
SignBase::Error Verify::VerifyFinal(const EVPKeyPointer& pkey,
const ByteSource& sig,
int padding,
const Maybe<int>& saltlen,
@ -555,8 +554,9 @@ void Verify::VerifyFinal(const FunctionCallbackInfo<Value>& 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<bool> SignTraits::AdditionalConfig(
params->mode =
static_cast<SignConfiguration::Mode>(args[offset].As<Uint32>()->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<bool>();
params->key = std::move(data);
} else {
key = ManagedEVPPKey::GetPrivateKeyFromJs(args, &keyParamOffset, true);
auto data = KeyObjectData::GetPrivateKeyFromJs(args, &keyParamOffset, true);
if (!data) return Nothing<bool>();
params->key = std::move(data);
}
if (!key)
return Nothing<bool>();
params->key = key;
ArrayBufferOrViewContents<char> data(args[offset + 5]);
if (UNLIKELY(!data.CheckSizeInt32())) {
@ -698,11 +699,10 @@ Maybe<bool> 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<int> salt_length = params.flags & SignConfiguration::kHasSaltLength
? Just<int>(params.salt_length) : Nothing<int>();
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);
}

View file

@ -60,11 +60,10 @@ class Sign : public SignBase {
: error(err), signature(std::move(sig)) {}
};
SignResult SignFinal(
const ManagedEVPPKey& pkey,
int padding,
const v8::Maybe<int>& saltlen,
DSASigEnc dsa_sig_enc);
SignResult SignFinal(const EVPKeyPointer& pkey,
int padding,
const v8::Maybe<int>& saltlen,
DSASigEnc dsa_sig_enc);
static void SignSync(const v8::FunctionCallbackInfo<v8::Value>& args);
@ -82,7 +81,7 @@ class Verify : public SignBase {
static void Initialize(Environment* env, v8::Local<v8::Object> target);
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
Error VerifyFinal(const ManagedEVPPKey& key,
Error VerifyFinal(const EVPKeyPointer& key,
const ByteSource& sig,
int padding,
const v8::Maybe<int>& 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;

View file

@ -422,8 +422,8 @@ ByteSource ByteSource::FromSymmetricKeyObjectHandle(Local<Value> handle) {
KeyObjectHandle* key =
BaseObject::Unwrap<KeyObjectHandle>(handle.As<Object>());
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) {

View file

@ -371,11 +371,11 @@ void PublicKey(const FunctionCallbackInfo<Value>& args) {
ThrowCryptoError(env, result.error.value_or(0));
return;
}
std::shared_ptr<KeyObjectData> key_data = KeyObjectData::CreateAsymmetric(
kKeyTypePublic, ManagedEVPPKey(std::move(result.value)));
auto key_data =
KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(result.value));
Local<Value> 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<Value>& 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<Value>& args) {
@ -425,10 +425,11 @@ void CheckPublicKey(const FunctionCallbackInfo<Value>& 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<Value>& args) {

View file

@ -92,12 +92,11 @@ bool SetOption(Environment* env,
if (!values->Get(context, n).ToLocal(&item)) {
return false;
}
if constexpr (std::is_same<T, std::shared_ptr<crypto::KeyObjectData>>::
value) {
if constexpr (std::is_same<T, crypto::KeyObjectData>::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<T,
std::shared_ptr<crypto::KeyObjectData>>::value) {
if constexpr (std::is_same<T, crypto::KeyObjectData>::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> 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<crypto::KeyObjectData>, keys) ||
!SET(keylog) || !SET_VECTOR(crypto::KeyObjectData, keys) ||
!SET_VECTOR(Store, certs) || !SET_VECTOR(Store, ca) ||
!SET_VECTOR(Store, crl)) {
return Nothing<Options>();

View file

@ -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<std::shared_ptr<crypto::KeyObjectData>> keys;
std::vector<crypto::KeyObjectData> keys;
// Collection of certificates to use for this session.
// JavaScript option name "certs"