1 #ifndef SRC_CRYPTO_CRYPTO_KEYGEN_H_ 2 #define SRC_CRYPTO_CRYPTO_KEYGEN_H_ 3 4 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 5 6 #include "async_wrap.h" 7 #include "base_object.h" 8 #include "crypto/crypto_keys.h" 9 #include "crypto/crypto_util.h" 10 #include "env.h" 11 #include "memory_tracker.h" 12 #include "v8.h" 13 14 namespace node { 15 namespace crypto { 16 namespace Keygen { 17 void Initialize(Environment* env, v8::Local<v8::Object> target); 18 void RegisterExternalReferences(ExternalReferenceRegistry* registry); 19 } // namespace Keygen 20 21 enum class KeyGenJobStatus { 22 OK, 23 FAILED 24 }; 25 26 // A Base CryptoJob for generating secret keys or key pairs. 27 // The KeyGenTraits is largely responsible for the details of 28 // the implementation, while KeyGenJob handles the common 29 // mechanisms. 30 template <typename KeyGenTraits> 31 class KeyGenJob final : public CryptoJob<KeyGenTraits> { 32 public: 33 using AdditionalParams = typename KeyGenTraits::AdditionalParameters; 34 New(const v8::FunctionCallbackInfo<v8::Value> & args)35 static void New(const v8::FunctionCallbackInfo<v8::Value>& args) { 36 Environment* env = Environment::GetCurrent(args); 37 CHECK(args.IsConstructCall()); 38 39 CryptoJobMode mode = GetCryptoJobMode(args[0]); 40 41 unsigned int offset = 1; 42 43 AdditionalParams params; 44 if (KeyGenTraits::AdditionalConfig(mode, args, &offset, ¶ms) 45 .IsNothing()) { 46 // The KeyGenTraits::AdditionalConfig is responsible for 47 // calling an appropriate THROW_CRYPTO_* variant reporting 48 // whatever error caused initialization to fail. 49 return; 50 } 51 52 new KeyGenJob<KeyGenTraits>(env, args.This(), mode, std::move(params)); 53 } 54 Initialize(Environment * env,v8::Local<v8::Object> target)55 static void Initialize( 56 Environment* env, 57 v8::Local<v8::Object> target) { 58 CryptoJob<KeyGenTraits>::Initialize(New, env, target); 59 } 60 RegisterExternalReferences(ExternalReferenceRegistry * registry)61 static void RegisterExternalReferences(ExternalReferenceRegistry* registry) { 62 CryptoJob<KeyGenTraits>::RegisterExternalReferences(New, registry); 63 } 64 KeyGenJob(Environment * env,v8::Local<v8::Object> object,CryptoJobMode mode,AdditionalParams && params)65 KeyGenJob( 66 Environment* env, 67 v8::Local<v8::Object> object, 68 CryptoJobMode mode, 69 AdditionalParams&& params) 70 : CryptoJob<KeyGenTraits>( 71 env, 72 object, 73 KeyGenTraits::Provider, 74 mode, 75 std::move(params)) {} 76 DoThreadPoolWork()77 void DoThreadPoolWork() override { 78 AdditionalParams* params = CryptoJob<KeyGenTraits>::params(); 79 80 switch (KeyGenTraits::DoKeyGen(AsyncWrap::env(), params)) { 81 case KeyGenJobStatus::OK: 82 status_ = KeyGenJobStatus::OK; 83 // Success! 84 break; 85 case KeyGenJobStatus::FAILED: { 86 CryptoErrorStore* errors = CryptoJob<KeyGenTraits>::errors(); 87 errors->Capture(); 88 if (errors->Empty()) 89 errors->Insert(NodeCryptoError::KEY_GENERATION_JOB_FAILED); 90 } 91 } 92 } 93 ToResult(v8::Local<v8::Value> * err,v8::Local<v8::Value> * result)94 v8::Maybe<bool> ToResult( 95 v8::Local<v8::Value>* err, 96 v8::Local<v8::Value>* result) override { 97 Environment* env = AsyncWrap::env(); 98 CryptoErrorStore* errors = CryptoJob<KeyGenTraits>::errors(); 99 AdditionalParams* params = CryptoJob<KeyGenTraits>::params(); 100 101 if (status_ == KeyGenJobStatus::OK) { 102 v8::Maybe<bool> ret = KeyGenTraits::EncodeKey(env, params, result); 103 if (ret.IsJust() && ret.FromJust()) { 104 *err = Undefined(env->isolate()); 105 } 106 return ret; 107 } 108 109 if (errors->Empty()) 110 errors->Capture(); 111 CHECK(!errors->Empty()); 112 *result = Undefined(env->isolate()); 113 return v8::Just(errors->ToException(env).ToLocal(err)); 114 } 115 116 SET_SELF_SIZE(KeyGenJob) 117 118 private: 119 KeyGenJobStatus status_ = KeyGenJobStatus::FAILED; 120 }; 121 122 // A Base KeyGenTraits for Key Pair generation algorithms. 123 template <typename KeyPairAlgorithmTraits> 124 struct KeyPairGenTraits final { 125 using AdditionalParameters = 126 typename KeyPairAlgorithmTraits::AdditionalParameters; 127 128 static const AsyncWrap::ProviderType Provider = 129 AsyncWrap::PROVIDER_KEYPAIRGENREQUEST; 130 static constexpr const char* JobName = KeyPairAlgorithmTraits::JobName; 131 AdditionalConfigfinal132 static v8::Maybe<bool> AdditionalConfig( 133 CryptoJobMode mode, 134 const v8::FunctionCallbackInfo<v8::Value>& args, 135 unsigned int* offset, 136 AdditionalParameters* params) { 137 // Notice that offset is a pointer. Each of the AdditionalConfig, 138 // GetPublicKeyEncodingFromJs, and GetPrivateKeyEncodingFromJs 139 // functions will update the value of the offset as they successfully 140 // process input parameters. This allows each job to have a variable 141 // number of input parameters specific to each job type. 142 if (KeyPairAlgorithmTraits::AdditionalConfig(mode, args, offset, params) 143 .IsNothing()) { 144 return v8::Just(false); 145 } 146 147 params->public_key_encoding = ManagedEVPPKey::GetPublicKeyEncodingFromJs( 148 args, 149 offset, 150 kKeyContextGenerate); 151 152 auto private_key_encoding = 153 ManagedEVPPKey::GetPrivateKeyEncodingFromJs( 154 args, 155 offset, 156 kKeyContextGenerate); 157 158 if (!private_key_encoding.IsEmpty()) 159 params->private_key_encoding = private_key_encoding.Release(); 160 161 return v8::Just(true); 162 } 163 DoKeyGenfinal164 static KeyGenJobStatus DoKeyGen( 165 Environment* env, 166 AdditionalParameters* params) { 167 EVPKeyCtxPointer ctx = KeyPairAlgorithmTraits::Setup(params); 168 169 if (!ctx) 170 return KeyGenJobStatus::FAILED; 171 172 // Generate the key 173 EVP_PKEY* pkey = nullptr; 174 if (!EVP_PKEY_keygen(ctx.get(), &pkey)) 175 return KeyGenJobStatus::FAILED; 176 177 params->key = ManagedEVPPKey(EVPKeyPointer(pkey)); 178 return KeyGenJobStatus::OK; 179 } 180 EncodeKeyfinal181 static v8::Maybe<bool> EncodeKey( 182 Environment* env, 183 AdditionalParameters* params, 184 v8::Local<v8::Value>* result) { 185 v8::Local<v8::Value> keys[2]; 186 if (params->key 187 .ToEncodedPublicKey(env, params->public_key_encoding, &keys[0]) 188 .IsNothing() || 189 params->key 190 .ToEncodedPrivateKey(env, params->private_key_encoding, &keys[1]) 191 .IsNothing()) { 192 return v8::Nothing<bool>(); 193 } 194 *result = v8::Array::New(env->isolate(), keys, arraysize(keys)); 195 return v8::Just(true); 196 } 197 }; 198 199 struct SecretKeyGenConfig final : public MemoryRetainer { 200 size_t length; // In bytes. 201 char* out = nullptr; // Placeholder for the generated key bytes. 202 203 void MemoryInfo(MemoryTracker* tracker) const override; 204 SET_MEMORY_INFO_NAME(SecretKeyGenConfig) 205 SET_SELF_SIZE(SecretKeyGenConfig) 206 }; 207 208 struct SecretKeyGenTraits final { 209 using AdditionalParameters = SecretKeyGenConfig; 210 static const AsyncWrap::ProviderType Provider = 211 AsyncWrap::PROVIDER_KEYGENREQUEST; 212 static constexpr const char* JobName = "SecretKeyGenJob"; 213 214 static v8::Maybe<bool> AdditionalConfig( 215 CryptoJobMode mode, 216 const v8::FunctionCallbackInfo<v8::Value>& args, 217 unsigned int* offset, 218 SecretKeyGenConfig* params); 219 220 static KeyGenJobStatus DoKeyGen( 221 Environment* env, 222 SecretKeyGenConfig* params); 223 224 static v8::Maybe<bool> EncodeKey( 225 Environment* env, 226 SecretKeyGenConfig* params, 227 v8::Local<v8::Value>* result); 228 }; 229 230 template <typename AlgorithmParams> 231 struct KeyPairGenConfig final : public MemoryRetainer { 232 PublicKeyEncodingConfig public_key_encoding; 233 PrivateKeyEncodingConfig private_key_encoding; 234 ManagedEVPPKey key; 235 AlgorithmParams params; 236 237 KeyPairGenConfig() = default; ~KeyPairGenConfigfinal238 ~KeyPairGenConfig() { 239 Mutex::ScopedLock priv_lock(*key.mutex()); 240 } 241 KeyPairGenConfigfinal242 explicit KeyPairGenConfig(KeyPairGenConfig&& other) noexcept 243 : public_key_encoding(other.public_key_encoding), 244 private_key_encoding( 245 std::forward<PrivateKeyEncodingConfig>( 246 other.private_key_encoding)), 247 key(std::move(other.key)), 248 params(std::move(other.params)) {} 249 250 KeyPairGenConfig& operator=(KeyPairGenConfig&& other) noexcept { 251 if (&other == this) return *this; 252 this->~KeyPairGenConfig(); 253 return *new (this) KeyPairGenConfig(std::move(other)); 254 } 255 MemoryInfofinal256 void MemoryInfo(MemoryTracker* tracker) const override { 257 tracker->TrackField("key", key); 258 if (!private_key_encoding.passphrase_.IsEmpty()) { 259 tracker->TrackFieldWithSize("private_key_encoding.passphrase", 260 private_key_encoding.passphrase_->size()); 261 } 262 tracker->TrackField("params", params); 263 } 264 265 SET_MEMORY_INFO_NAME(KeyPairGenConfig) 266 SET_SELF_SIZE(KeyPairGenConfig) 267 }; 268 269 struct NidKeyPairParams final : public MemoryRetainer { 270 int id; 271 SET_NO_MEMORY_INFO() 272 SET_MEMORY_INFO_NAME(NidKeyPairParams) 273 SET_SELF_SIZE(NidKeyPairParams) 274 }; 275 276 using NidKeyPairGenConfig = KeyPairGenConfig<NidKeyPairParams>; 277 278 struct NidKeyPairGenTraits final { 279 using AdditionalParameters = NidKeyPairGenConfig; 280 static constexpr const char* JobName = "NidKeyPairGenJob"; 281 282 static EVPKeyCtxPointer Setup(NidKeyPairGenConfig* params); 283 284 static v8::Maybe<bool> AdditionalConfig( 285 CryptoJobMode mode, 286 const v8::FunctionCallbackInfo<v8::Value>& args, 287 unsigned int* offset, 288 NidKeyPairGenConfig* params); 289 }; 290 291 using NidKeyPairGenJob = KeyGenJob<KeyPairGenTraits<NidKeyPairGenTraits>>; 292 using SecretKeyGenJob = KeyGenJob<SecretKeyGenTraits>; 293 } // namespace crypto 294 } // namespace node 295 296 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 297 #endif // SRC_CRYPTO_CRYPTO_KEYGEN_H_ 298 299