GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_keygen.h Lines: 67 93 72.0 %
Date: 2021-12-25 04:14:02 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
702
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
37
702
    Environment* env = Environment::GetCurrent(args);
38
702
    CHECK(args.IsConstructCall());
39
40
702
    CryptoJobMode mode = GetCryptoJobMode(args[0]);
41
42
702
    unsigned int offset = 1;
43
44
702
    AdditionalParams params;
45
1404
    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
702
    new KeyGenJob<KeyGenTraits>(env, args.This(), mode, std::move(params));
54
  }
55
56
34736
  static void Initialize(
57
      Environment* env,
58
      v8::Local<v8::Object> target) {
59
34736
    CryptoJob<KeyGenTraits>::Initialize(New, env, target);
60
34736
  }
61
62
39200
  static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
63
39200
    CryptoJob<KeyGenTraits>::RegisterExternalReferences(New, registry);
64
39200
  }
65
66
702
  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
702
            std::move(params)) {}
77
78
695
  void DoThreadPoolWork() override {
79
    // Make sure the CSPRNG is properly seeded so the results are secure.
80
695
    CheckEntropy();
81
82
695
    AdditionalParams* params = CryptoJob<KeyGenTraits>::params();
83
84
695
    switch (KeyGenTraits::DoKeyGen(AsyncWrap::env(), params)) {
85
695
      case KeyGenJobStatus::OK:
86
695
        status_ = KeyGenJobStatus::OK;
87
        // Success!
88
695
        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
695
  }
97
98
694
  v8::Maybe<bool> ToResult(
99
      v8::Local<v8::Value>* err,
100
      v8::Local<v8::Value>* result) override {
101
694
    Environment* env = AsyncWrap::env();
102
694
    CryptoErrorStore* errors = CryptoJob<KeyGenTraits>::errors();
103
694
    AdditionalParams* params = CryptoJob<KeyGenTraits>::params();
104
105
694
    if (status_ == KeyGenJobStatus::OK) {
106
694
      v8::Maybe<bool> ret = KeyGenTraits::EncodeKey(env, params, result);
107

1383
      if (ret.IsJust() && ret.FromJust()) {
108
1378
        *err = Undefined(env->isolate());
109
      }
110
694
      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
308
  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
616
    if (KeyPairAlgorithmTraits::AdditionalConfig(mode, args, offset, params)
147
            .IsNothing()) {
148
6
      return v8::Just(false);
149
    }
150
151
302
    params->public_key_encoding = ManagedEVPPKey::GetPublicKeyEncodingFromJs(
152
        args,
153
        offset,
154
        kKeyContextGenerate);
155
156
302
    auto private_key_encoding =
157
        ManagedEVPPKey::GetPrivateKeyEncodingFromJs(
158
            args,
159
            offset,
160
            kKeyContextGenerate);
161
162
302
    if (!private_key_encoding.IsEmpty())
163
301
      params->private_key_encoding = private_key_encoding.Release();
164
165
302
    return v8::Just(true);
166
  }
167
168
301
  static KeyGenJobStatus DoKeyGen(
169
      Environment* env,
170
      AdditionalParameters* params) {
171
602
    EVPKeyCtxPointer ctx = KeyPairAlgorithmTraits::Setup(params);
172
173
301
    if (!ctx)
174
      return KeyGenJobStatus::FAILED;
175
176
    // Generate the key
177
301
    EVP_PKEY* pkey = nullptr;
178
301
    if (!EVP_PKEY_keygen(ctx.get(), &pkey))
179
      return KeyGenJobStatus::FAILED;
180
181
301
    params->key = ManagedEVPPKey(EVPKeyPointer(pkey));
182
301
    return KeyGenJobStatus::OK;
183
  }
184
185
300
  static v8::Maybe<bool> EncodeKey(
186
      Environment* env,
187
      AdditionalParameters* params,
188
      v8::Local<v8::Value>* result) {
189
900
    v8::Local<v8::Value> keys[2];
190
600
    if (ManagedEVPPKey::ToEncodedPublicKey(
191
            env,
192
300
            std::move(params->key),
193
300
            params->public_key_encoding,
194

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

595
        ManagedEVPPKey::ToEncodedPrivateKey(
196
            env,
197
295
            std::move(params->key),
198
295
            params->private_key_encoding,
199
            &keys[1]).IsNothing()) {
200
5
      return v8::Nothing<bool>();
201
    }
202
295
    *result = v8::Array::New(env->isolate(), keys, arraysize(keys));
203
295
    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
308
  KeyPairGenConfig() = default;
246
1230
  ~KeyPairGenConfig() {
247
1230
    Mutex::ScopedLock priv_lock(*key.mutex());
248
  }
249
250
308
  explicit KeyPairGenConfig(KeyPairGenConfig&& other) noexcept
251
      : public_key_encoding(other.public_key_encoding),
252
        private_key_encoding(
253
            std::forward<PrivateKeyEncodingConfig>(
254
308
                other.private_key_encoding)),
255
308
        key(std::move(other.key)),
256
308
        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