| #ifndef SRC_CRYPTO_CRYPTO_KEYGEN_H_ |
| #define SRC_CRYPTO_CRYPTO_KEYGEN_H_ |
| |
| #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
| |
| #include "async_wrap.h" |
| #include "base_object.h" |
| #include "crypto/crypto_keys.h" |
| #include "crypto/crypto_util.h" |
| #include "env.h" |
| #include "memory_tracker.h" |
| #include "v8.h" |
| |
| namespace node { |
| namespace crypto { |
| namespace Keygen { |
| void Initialize(Environment* env, v8::Local<v8::Object> target); |
| void RegisterExternalReferences(ExternalReferenceRegistry* registry); |
| } // namespace Keygen |
| |
| enum class KeyGenJobStatus { |
| OK, |
| FAILED |
| }; |
| |
| // A Base CryptoJob for generating secret keys or key pairs. |
| // The KeyGenTraits is largely responsible for the details of |
| // the implementation, while KeyGenJob handles the common |
| // mechanisms. |
| template <typename KeyGenTraits> |
| class KeyGenJob final : public CryptoJob<KeyGenTraits> { |
| public: |
| using AdditionalParams = typename KeyGenTraits::AdditionalParameters; |
| |
| static void New(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| Environment* env = Environment::GetCurrent(args); |
| CHECK(args.IsConstructCall()); |
| |
| CryptoJobMode mode = GetCryptoJobMode(args[0]); |
| |
| unsigned int offset = 1; |
| |
| AdditionalParams params; |
| if (KeyGenTraits::AdditionalConfig(mode, args, &offset, ¶ms) |
| .IsNothing()) { |
| // The KeyGenTraits::AdditionalConfig is responsible for |
| // calling an appropriate THROW_CRYPTO_* variant reporting |
| // whatever error caused initialization to fail. |
| return; |
| } |
| |
| new KeyGenJob<KeyGenTraits>(env, args.This(), mode, std::move(params)); |
| } |
| |
| static void Initialize( |
| Environment* env, |
| v8::Local<v8::Object> target) { |
| CryptoJob<KeyGenTraits>::Initialize(New, env, target); |
| } |
| |
| static void RegisterExternalReferences(ExternalReferenceRegistry* registry) { |
| CryptoJob<KeyGenTraits>::RegisterExternalReferences(New, registry); |
| } |
| |
| KeyGenJob( |
| Environment* env, |
| v8::Local<v8::Object> object, |
| CryptoJobMode mode, |
| AdditionalParams&& params) |
| : CryptoJob<KeyGenTraits>( |
| env, |
| object, |
| KeyGenTraits::Provider, |
| mode, |
| std::move(params)) {} |
| |
| void DoThreadPoolWork() override { |
| AdditionalParams* params = CryptoJob<KeyGenTraits>::params(); |
| |
| switch (KeyGenTraits::DoKeyGen(AsyncWrap::env(), params)) { |
| case KeyGenJobStatus::OK: |
| status_ = KeyGenJobStatus::OK; |
| // Success! |
| break; |
| case KeyGenJobStatus::FAILED: { |
| CryptoErrorStore* errors = CryptoJob<KeyGenTraits>::errors(); |
| errors->Capture(); |
| if (errors->Empty()) |
| errors->Insert(NodeCryptoError::KEY_GENERATION_JOB_FAILED); |
| } |
| } |
| } |
| |
| v8::Maybe<bool> ToResult( |
| v8::Local<v8::Value>* err, |
| v8::Local<v8::Value>* result) override { |
| Environment* env = AsyncWrap::env(); |
| CryptoErrorStore* errors = CryptoJob<KeyGenTraits>::errors(); |
| AdditionalParams* params = CryptoJob<KeyGenTraits>::params(); |
| |
| if (status_ == KeyGenJobStatus::OK) { |
| v8::Maybe<bool> ret = KeyGenTraits::EncodeKey(env, params, result); |
| if (ret.IsJust() && ret.FromJust()) { |
| *err = Undefined(env->isolate()); |
| } |
| return ret; |
| } |
| |
| if (errors->Empty()) |
| errors->Capture(); |
| CHECK(!errors->Empty()); |
| *result = Undefined(env->isolate()); |
| return v8::Just(errors->ToException(env).ToLocal(err)); |
| } |
| |
| SET_SELF_SIZE(KeyGenJob) |
| |
| private: |
| KeyGenJobStatus status_ = KeyGenJobStatus::FAILED; |
| }; |
| |
| // A Base KeyGenTraits for Key Pair generation algorithms. |
| template <typename KeyPairAlgorithmTraits> |
| struct KeyPairGenTraits final { |
| using AdditionalParameters = |
| typename KeyPairAlgorithmTraits::AdditionalParameters; |
| |
| static const AsyncWrap::ProviderType Provider = |
| AsyncWrap::PROVIDER_KEYPAIRGENREQUEST; |
| static constexpr const char* JobName = KeyPairAlgorithmTraits::JobName; |
| |
| static v8::Maybe<bool> AdditionalConfig( |
| CryptoJobMode mode, |
| const v8::FunctionCallbackInfo<v8::Value>& args, |
| unsigned int* offset, |
| AdditionalParameters* params) { |
| // Notice that offset is a pointer. Each of the AdditionalConfig, |
| // GetPublicKeyEncodingFromJs, and GetPrivateKeyEncodingFromJs |
| // functions will update the value of the offset as they successfully |
| // process input parameters. This allows each job to have a variable |
| // number of input parameters specific to each job type. |
| if (KeyPairAlgorithmTraits::AdditionalConfig(mode, args, offset, params) |
| .IsNothing()) { |
| return v8::Just(false); |
| } |
| |
| params->public_key_encoding = ManagedEVPPKey::GetPublicKeyEncodingFromJs( |
| args, |
| offset, |
| kKeyContextGenerate); |
| |
| auto private_key_encoding = |
| ManagedEVPPKey::GetPrivateKeyEncodingFromJs( |
| args, |
| offset, |
| kKeyContextGenerate); |
| |
| if (!private_key_encoding.IsEmpty()) |
| params->private_key_encoding = private_key_encoding.Release(); |
| |
| return v8::Just(true); |
| } |
| |
| static KeyGenJobStatus DoKeyGen( |
| Environment* env, |
| AdditionalParameters* params) { |
| EVPKeyCtxPointer ctx = KeyPairAlgorithmTraits::Setup(params); |
| |
| if (!ctx) |
| return KeyGenJobStatus::FAILED; |
| |
| // Generate the key |
| EVP_PKEY* pkey = nullptr; |
| if (!EVP_PKEY_keygen(ctx.get(), &pkey)) |
| return KeyGenJobStatus::FAILED; |
| |
| params->key = ManagedEVPPKey(EVPKeyPointer(pkey)); |
| return KeyGenJobStatus::OK; |
| } |
| |
| static v8::Maybe<bool> EncodeKey( |
| Environment* env, |
| AdditionalParameters* params, |
| v8::Local<v8::Value>* result) { |
| v8::Local<v8::Value> keys[2]; |
| if (params->key |
| .ToEncodedPublicKey(env, params->public_key_encoding, &keys[0]) |
| .IsNothing() || |
| params->key |
| .ToEncodedPrivateKey(env, params->private_key_encoding, &keys[1]) |
| .IsNothing()) { |
| return v8::Nothing<bool>(); |
| } |
| *result = v8::Array::New(env->isolate(), keys, arraysize(keys)); |
| return v8::Just(true); |
| } |
| }; |
| |
| struct SecretKeyGenConfig final : public MemoryRetainer { |
| size_t length; // In bytes. |
| ByteSource out; // Placeholder for the generated key bytes. |
| |
| void MemoryInfo(MemoryTracker* tracker) const override; |
| SET_MEMORY_INFO_NAME(SecretKeyGenConfig) |
| SET_SELF_SIZE(SecretKeyGenConfig) |
| }; |
| |
| struct SecretKeyGenTraits final { |
| using AdditionalParameters = SecretKeyGenConfig; |
| static const AsyncWrap::ProviderType Provider = |
| AsyncWrap::PROVIDER_KEYGENREQUEST; |
| static constexpr const char* JobName = "SecretKeyGenJob"; |
| |
| static v8::Maybe<bool> AdditionalConfig( |
| CryptoJobMode mode, |
| const v8::FunctionCallbackInfo<v8::Value>& args, |
| unsigned int* offset, |
| SecretKeyGenConfig* params); |
| |
| static KeyGenJobStatus DoKeyGen( |
| Environment* env, |
| SecretKeyGenConfig* params); |
| |
| static v8::Maybe<bool> EncodeKey( |
| Environment* env, |
| SecretKeyGenConfig* params, |
| v8::Local<v8::Value>* result); |
| }; |
| |
| template <typename AlgorithmParams> |
| struct KeyPairGenConfig final : public MemoryRetainer { |
| PublicKeyEncodingConfig public_key_encoding; |
| PrivateKeyEncodingConfig private_key_encoding; |
| ManagedEVPPKey key; |
| AlgorithmParams params; |
| |
| KeyPairGenConfig() = default; |
| ~KeyPairGenConfig() { |
| Mutex::ScopedLock priv_lock(*key.mutex()); |
| } |
| |
| explicit KeyPairGenConfig(KeyPairGenConfig&& other) noexcept |
| : public_key_encoding(other.public_key_encoding), |
| private_key_encoding( |
| std::forward<PrivateKeyEncodingConfig>( |
| other.private_key_encoding)), |
| key(std::move(other.key)), |
| params(std::move(other.params)) {} |
| |
| KeyPairGenConfig& operator=(KeyPairGenConfig&& other) noexcept { |
| if (&other == this) return *this; |
| this->~KeyPairGenConfig(); |
| return *new (this) KeyPairGenConfig(std::move(other)); |
| } |
| |
| void MemoryInfo(MemoryTracker* tracker) const override { |
| tracker->TrackField("key", key); |
| if (!private_key_encoding.passphrase_.IsEmpty()) { |
| tracker->TrackFieldWithSize("private_key_encoding.passphrase", |
| private_key_encoding.passphrase_->size()); |
| } |
| tracker->TrackField("params", params); |
| } |
| |
| SET_MEMORY_INFO_NAME(KeyPairGenConfig) |
| SET_SELF_SIZE(KeyPairGenConfig) |
| }; |
| |
| struct NidKeyPairParams final : public MemoryRetainer { |
| int id; |
| SET_NO_MEMORY_INFO() |
| SET_MEMORY_INFO_NAME(NidKeyPairParams) |
| SET_SELF_SIZE(NidKeyPairParams) |
| }; |
| |
| using NidKeyPairGenConfig = KeyPairGenConfig<NidKeyPairParams>; |
| |
| struct NidKeyPairGenTraits final { |
| using AdditionalParameters = NidKeyPairGenConfig; |
| static constexpr const char* JobName = "NidKeyPairGenJob"; |
| |
| static EVPKeyCtxPointer Setup(NidKeyPairGenConfig* params); |
| |
| static v8::Maybe<bool> AdditionalConfig( |
| CryptoJobMode mode, |
| const v8::FunctionCallbackInfo<v8::Value>& args, |
| unsigned int* offset, |
| NidKeyPairGenConfig* params); |
| }; |
| |
| using NidKeyPairGenJob = KeyGenJob<KeyPairGenTraits<NidKeyPairGenTraits>>; |
| using SecretKeyGenJob = KeyGenJob<SecretKeyGenTraits>; |
| } // namespace crypto |
| } // namespace node |
| |
| #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
| #endif // SRC_CRYPTO_CRYPTO_KEYGEN_H_ |
| |