GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_keygen.h Lines: 76 93 81.7 %
Date: 2022-06-17 04:15:42 Branches: 31 43 72.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 "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
35
579
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
36
579
    Environment* env = Environment::GetCurrent(args);
37
579
    CHECK(args.IsConstructCall());
38
39
579
    CryptoJobMode mode = GetCryptoJobMode(args[0]);
40
41
579
    unsigned int offset = 1;
42
43
579
    AdditionalParams params;
44
1158
    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
579
    new KeyGenJob<KeyGenTraits>(env, args.This(), mode, std::move(params));
53
  }
54
55
6816
  static void Initialize(
56
      Environment* env,
57
      v8::Local<v8::Object> target) {
58
6816
    CryptoJob<KeyGenTraits>::Initialize(New, env, target);
59
6816
  }
60
61
41639
  static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
62
41639
    CryptoJob<KeyGenTraits>::RegisterExternalReferences(New, registry);
63
41639
  }
64
65
579
  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
579
            std::move(params)) {}
76
77
576
  void DoThreadPoolWork() override {
78
    // Make sure the CSPRNG is properly seeded so the results are secure.
79
576
    CheckEntropy();
80
81
576
    AdditionalParams* params = CryptoJob<KeyGenTraits>::params();
82
83
576
    switch (KeyGenTraits::DoKeyGen(AsyncWrap::env(), params)) {
84
494
      case KeyGenJobStatus::OK:
85
494
        status_ = KeyGenJobStatus::OK;
86
        // Success!
87
494
        break;
88
82
      case KeyGenJobStatus::FAILED: {
89
82
        CryptoErrorStore* errors = CryptoJob<KeyGenTraits>::errors();
90
82
        errors->Capture();
91
82
        if (errors->Empty())
92
          errors->Insert(NodeCryptoError::KEY_GENERATION_JOB_FAILED);
93
      }
94
    }
95
576
  }
96
97
575
  v8::Maybe<bool> ToResult(
98
      v8::Local<v8::Value>* err,
99
      v8::Local<v8::Value>* result) override {
100
575
    Environment* env = AsyncWrap::env();
101
575
    CryptoErrorStore* errors = CryptoJob<KeyGenTraits>::errors();
102
575
    AdditionalParams* params = CryptoJob<KeyGenTraits>::params();
103
104
575
    if (status_ == KeyGenJobStatus::OK) {
105
493
      v8::Maybe<bool> ret = KeyGenTraits::EncodeKey(env, params, result);
106

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

622
            &keys[0]).IsNothing() ||
194

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