• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &params)
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