GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_keygen.h Lines: 67 93 72.0 %
Date: 2022-05-07 04:15:18 Branches: 25 43 58.1 %

Line Branch Exec Source
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 "crypto/crypto_keys.h"
7
#include "crypto/crypto_util.h"
8
#include "allocated_buffer.h"
9
#include "async_wrap.h"
10
#include "base_object.h"
11
#include "env.h"
12
#include "memory_tracker.h"
13
#include "v8.h"
14
15
namespace node {
16
namespace crypto {
17
namespace Keygen {
18
void Initialize(Environment* env, v8::Local<v8::Object> target);
19
void RegisterExternalReferences(ExternalReferenceRegistry* registry);
20
}  // namespace Keygen
21
22
enum class KeyGenJobStatus {
23
  OK,
24
  FAILED
25
};
26
27
// A Base CryptoJob for generating secret keys or key pairs.
28
// The KeyGenTraits is largely responsible for the details of
29
// the implementation, while KeyGenJob handles the common
30
// mechanisms.
31
template <typename KeyGenTraits>
32
class KeyGenJob final : public CryptoJob<KeyGenTraits> {
33
 public:
34
  using AdditionalParams = typename KeyGenTraits::AdditionalParameters;
35
36
717
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
37
717
    Environment* env = Environment::GetCurrent(args);
38
717
    CHECK(args.IsConstructCall());
39
40
717
    CryptoJobMode mode = GetCryptoJobMode(args[0]);
41
42
717
    unsigned int offset = 1;
43
44
717
    AdditionalParams params;
45
1434
    if (KeyGenTraits::AdditionalConfig(mode, args, &offset, &params)
46
            .IsNothing()) {
47
      // The KeyGenTraits::AdditionalConfig is responsible for
48
      // calling an appropriate THROW_CRYPTO_* variant reporting
49
      // whatever error caused initialization to fail.
50
      return;
51
    }
52
53
717
    new KeyGenJob<KeyGenTraits>(env, args.This(), mode, std::move(params));
54
  }
55
56
6792
  static void Initialize(
57
      Environment* env,
58
      v8::Local<v8::Object> target) {
59
6792
    CryptoJob<KeyGenTraits>::Initialize(New, env, target);
60
6792
  }
61
62
41400
  static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
63
41400
    CryptoJob<KeyGenTraits>::RegisterExternalReferences(New, registry);
64
41400
  }
65
66
717
  KeyGenJob(
67
      Environment* env,
68
      v8::Local<v8::Object> object,
69
      CryptoJobMode mode,
70
      AdditionalParams&& params)
71
      : CryptoJob<KeyGenTraits>(
72
            env,
73
            object,
74
            KeyGenTraits::Provider,
75
            mode,
76
717
            std::move(params)) {}
77
78
710
  void DoThreadPoolWork() override {
79
    // Make sure the CSPRNG is properly seeded so the results are secure.
80
710
    CheckEntropy();
81
82
710
    AdditionalParams* params = CryptoJob<KeyGenTraits>::params();
83
84
710
    switch (KeyGenTraits::DoKeyGen(AsyncWrap::env(), params)) {
85
710
      case KeyGenJobStatus::OK:
86
710
        status_ = KeyGenJobStatus::OK;
87
        // Success!
88
710
        break;
89
      case KeyGenJobStatus::FAILED: {
90
        CryptoErrorStore* errors = CryptoJob<KeyGenTraits>::errors();
91
        errors->Capture();
92
        if (errors->Empty())
93
          errors->Insert(NodeCryptoError::KEY_GENERATION_JOB_FAILED);
94
      }
95
    }
96
710
  }
97
98
709
  v8::Maybe<bool> ToResult(
99
      v8::Local<v8::Value>* err,
100
      v8::Local<v8::Value>* result) override {
101
709
    Environment* env = AsyncWrap::env();
102
709
    CryptoErrorStore* errors = CryptoJob<KeyGenTraits>::errors();
103
709
    AdditionalParams* params = CryptoJob<KeyGenTraits>::params();
104
105
709
    if (status_ == KeyGenJobStatus::OK) {
106
709
      v8::Maybe<bool> ret = KeyGenTraits::EncodeKey(env, params, result);
107

1413
      if (ret.IsJust() && ret.FromJust()) {
108
1408
        *err = Undefined(env->isolate());
109
      }
110
709
      return ret;
111
    }
112
113
    if (errors->Empty())
114
      errors->Capture();
115
    CHECK(!errors->Empty());
116
    *result = Undefined(env->isolate());
117
    return v8::Just(errors->ToException(env).ToLocal(err));
118
  }
119
120
  SET_SELF_SIZE(KeyGenJob)
121
122
 private:
123
  KeyGenJobStatus status_ = KeyGenJobStatus::FAILED;
124
};
125
126
// A Base KeyGenTraits for Key Pair generation algorithms.
127
template <typename KeyPairAlgorithmTraits>
128
struct KeyPairGenTraits final {
129
  using AdditionalParameters =
130
      typename KeyPairAlgorithmTraits::AdditionalParameters;
131
132
  static const AsyncWrap::ProviderType Provider =
133
      AsyncWrap::PROVIDER_KEYPAIRGENREQUEST;
134
  static constexpr const char* JobName = KeyPairAlgorithmTraits::JobName;
135
136
317
  static v8::Maybe<bool> AdditionalConfig(
137
      CryptoJobMode mode,
138
      const v8::FunctionCallbackInfo<v8::Value>& args,
139
      unsigned int* offset,
140
      AdditionalParameters* params) {
141
    // Notice that offset is a pointer. Each of the AdditionalConfig,
142
    // GetPublicKeyEncodingFromJs, and GetPrivateKeyEncodingFromJs
143
    // functions will update the value of the offset as they successfully
144
    // process input parameters. This allows each job to have a variable
145
    // number of input parameters specific to each job type.
146
634
    if (KeyPairAlgorithmTraits::AdditionalConfig(mode, args, offset, params)
147
            .IsNothing()) {
148
6
      return v8::Just(false);
149
    }
150
151
311
    params->public_key_encoding = ManagedEVPPKey::GetPublicKeyEncodingFromJs(
152
        args,
153
        offset,
154
        kKeyContextGenerate);
155
156
311
    auto private_key_encoding =
157
        ManagedEVPPKey::GetPrivateKeyEncodingFromJs(
158
            args,
159
            offset,
160
            kKeyContextGenerate);
161
162
311
    if (!private_key_encoding.IsEmpty())
163
310
      params->private_key_encoding = private_key_encoding.Release();
164
165
311
    return v8::Just(true);
166
  }
167
168
310
  static KeyGenJobStatus DoKeyGen(
169
      Environment* env,
170
      AdditionalParameters* params) {
171
620
    EVPKeyCtxPointer ctx = KeyPairAlgorithmTraits::Setup(params);
172
173
310
    if (!ctx)
174
      return KeyGenJobStatus::FAILED;
175
176
    // Generate the key
177
310
    EVP_PKEY* pkey = nullptr;
178
310
    if (!EVP_PKEY_keygen(ctx.get(), &pkey))
179
      return KeyGenJobStatus::FAILED;
180
181
310
    params->key = ManagedEVPPKey(EVPKeyPointer(pkey));
182
310
    return KeyGenJobStatus::OK;
183
  }
184
185
309
  static v8::Maybe<bool> EncodeKey(
186
      Environment* env,
187
      AdditionalParameters* params,
188
      v8::Local<v8::Value>* result) {
189
927
    v8::Local<v8::Value> keys[2];
190
618
    if (ManagedEVPPKey::ToEncodedPublicKey(
191
            env,
192
309
            std::move(params->key),
193
309
            params->public_key_encoding,
194

922
            &keys[0]).IsNothing() ||
195

613
        ManagedEVPPKey::ToEncodedPrivateKey(
196
            env,
197
304
            std::move(params->key),
198
304
            params->private_key_encoding,
199
            &keys[1]).IsNothing()) {
200
5
      return v8::Nothing<bool>();
201
    }
202
304
    *result = v8::Array::New(env->isolate(), keys, arraysize(keys));
203
304
    return v8::Just(true);
204
  }
205
};
206
207
struct SecretKeyGenConfig final : public MemoryRetainer {
208
  size_t length;  // Expressed a a number of bits
209
  char* out = nullptr;  // Placeholder for the generated key bytes
210
211
  void MemoryInfo(MemoryTracker* tracker) const override;
212
  SET_MEMORY_INFO_NAME(SecretKeyGenConfig)
213
  SET_SELF_SIZE(SecretKeyGenConfig)
214
};
215
216
struct SecretKeyGenTraits final {
217
  using AdditionalParameters = SecretKeyGenConfig;
218
  static const AsyncWrap::ProviderType Provider =
219
      AsyncWrap::PROVIDER_KEYGENREQUEST;
220
  static constexpr const char* JobName = "SecretKeyGenJob";
221
222
  static v8::Maybe<bool> AdditionalConfig(
223
      CryptoJobMode mode,
224
      const v8::FunctionCallbackInfo<v8::Value>& args,
225
      unsigned int* offset,
226
      SecretKeyGenConfig* params);
227
228
  static KeyGenJobStatus DoKeyGen(
229
      Environment* env,
230
      SecretKeyGenConfig* params);
231
232
  static v8::Maybe<bool> EncodeKey(
233
      Environment* env,
234
      SecretKeyGenConfig* params,
235
      v8::Local<v8::Value>* result);
236
};
237
238
template <typename AlgorithmParams>
239
struct KeyPairGenConfig final : public MemoryRetainer {
240
  PublicKeyEncodingConfig public_key_encoding;
241
  PrivateKeyEncodingConfig private_key_encoding;
242
  ManagedEVPPKey key;
243
  AlgorithmParams params;
244
245
317
  KeyPairGenConfig() = default;
246
1266
  ~KeyPairGenConfig() {
247
1266
    Mutex::ScopedLock priv_lock(*key.mutex());
248
  }
249
250
317
  explicit KeyPairGenConfig(KeyPairGenConfig&& other) noexcept
251
      : public_key_encoding(other.public_key_encoding),
252
        private_key_encoding(
253
            std::forward<PrivateKeyEncodingConfig>(
254
317
                other.private_key_encoding)),
255
317
        key(std::move(other.key)),
256
317
        params(std::move(other.params)) {}
257
258
  KeyPairGenConfig& operator=(KeyPairGenConfig&& other) noexcept {
259
    if (&other == this) return *this;
260
    this->~KeyPairGenConfig();
261
    return *new (this) KeyPairGenConfig(std::move(other));
262
  }
263
264
  void MemoryInfo(MemoryTracker* tracker) const override {
265
    tracker->TrackField("key", key);
266
    if (!private_key_encoding.passphrase_.IsEmpty()) {
267
      tracker->TrackFieldWithSize("private_key_encoding.passphrase",
268
                                  private_key_encoding.passphrase_->size());
269
    }
270
    tracker->TrackField("params", params);
271
  }
272
273
  SET_MEMORY_INFO_NAME(KeyPairGenConfig)
274
  SET_SELF_SIZE(KeyPairGenConfig)
275
};
276
277
struct NidKeyPairParams final : public MemoryRetainer {
278
  int id;
279
  SET_NO_MEMORY_INFO()
280
  SET_MEMORY_INFO_NAME(NidKeyPairParams)
281
  SET_SELF_SIZE(NidKeyPairParams)
282
};
283
284
using NidKeyPairGenConfig = KeyPairGenConfig<NidKeyPairParams>;
285
286
struct NidKeyPairGenTraits final {
287
  using AdditionalParameters = NidKeyPairGenConfig;
288
  static constexpr const char* JobName = "NidKeyPairGenJob";
289
290
  static EVPKeyCtxPointer Setup(NidKeyPairGenConfig* params);
291
292
  static v8::Maybe<bool> AdditionalConfig(
293
      CryptoJobMode mode,
294
      const v8::FunctionCallbackInfo<v8::Value>& args,
295
      unsigned int* offset,
296
      NidKeyPairGenConfig* params);
297
};
298
299
using NidKeyPairGenJob = KeyGenJob<KeyPairGenTraits<NidKeyPairGenTraits>>;
300
using SecretKeyGenJob = KeyGenJob<SecretKeyGenTraits>;
301
}  // namespace crypto
302
}  // namespace node
303
304
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
305
#endif  // SRC_CRYPTO_CRYPTO_KEYGEN_H_
306