GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_keygen.h Lines: 73 90 81.1 %
Date: 2022-12-31 04:22:30 Branches: 28 39 71.8 %

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
3525
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
36
3525
    Environment* env = Environment::GetCurrent(args);
37
3525
    CHECK(args.IsConstructCall());
38
39
3525
    CryptoJobMode mode = GetCryptoJobMode(args[0]);
40
41
3525
    unsigned int offset = 1;
42
43
3525
    AdditionalParams params;
44
7050
    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
3525
    new KeyGenJob<KeyGenTraits>(env, args.This(), mode, std::move(params));
53
  }
54
55
40520
  static void Initialize(
56
      Environment* env,
57
      v8::Local<v8::Object> target) {
58
40520
    CryptoJob<KeyGenTraits>::Initialize(New, env, target);
59
40520
  }
60
61
45744
  static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
62
45744
    CryptoJob<KeyGenTraits>::RegisterExternalReferences(New, registry);
63
45744
  }
64
65
3525
  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
3525
            std::move(params)) {}
76
77
3520
  void DoThreadPoolWork() override {
78
3520
    AdditionalParams* params = CryptoJob<KeyGenTraits>::params();
79
80
3520
    switch (KeyGenTraits::DoKeyGen(AsyncWrap::env(), params)) {
81
3426
      case KeyGenJobStatus::OK:
82
3426
        status_ = KeyGenJobStatus::OK;
83
        // Success!
84
3426
        break;
85
94
      case KeyGenJobStatus::FAILED: {
86
94
        CryptoErrorStore* errors = CryptoJob<KeyGenTraits>::errors();
87
94
        errors->Capture();
88
94
        if (errors->Empty())
89
          errors->Insert(NodeCryptoError::KEY_GENERATION_JOB_FAILED);
90
      }
91
    }
92
3520
  }
93
94
3519
  v8::Maybe<bool> ToResult(
95
      v8::Local<v8::Value>* err,
96
      v8::Local<v8::Value>* result) override {
97
3519
    Environment* env = AsyncWrap::env();
98
3519
    CryptoErrorStore* errors = CryptoJob<KeyGenTraits>::errors();
99
3519
    AdditionalParams* params = CryptoJob<KeyGenTraits>::params();
100
101
3519
    if (status_ == KeyGenJobStatus::OK) {
102
3425
      v8::Maybe<bool> ret = KeyGenTraits::EncodeKey(env, params, result);
103

6845
      if (ret.IsJust() && ret.FromJust()) {
104
6840
        *err = Undefined(env->isolate());
105
      }
106
3425
      return ret;
107
    }
108
109
94
    if (errors->Empty())
110
      errors->Capture();
111
94
    CHECK(!errors->Empty());
112
188
    *result = Undefined(env->isolate());
113
188
    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
132
785
  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
1570
    if (KeyPairAlgorithmTraits::AdditionalConfig(mode, args, offset, params)
143
            .IsNothing()) {
144
4
      return v8::Just(false);
145
    }
146
147
781
    params->public_key_encoding = ManagedEVPPKey::GetPublicKeyEncodingFromJs(
148
        args,
149
        offset,
150
        kKeyContextGenerate);
151
152
781
    auto private_key_encoding =
153
        ManagedEVPPKey::GetPrivateKeyEncodingFromJs(
154
            args,
155
            offset,
156
            kKeyContextGenerate);
157
158
781
    if (!private_key_encoding.IsEmpty())
159
780
      params->private_key_encoding = private_key_encoding.Release();
160
161
781
    return v8::Just(true);
162
  }
163
164
780
  static KeyGenJobStatus DoKeyGen(
165
      Environment* env,
166
      AdditionalParameters* params) {
167
1560
    EVPKeyCtxPointer ctx = KeyPairAlgorithmTraits::Setup(params);
168
169
780
    if (!ctx)
170
      return KeyGenJobStatus::FAILED;
171
172
    // Generate the key
173
780
    EVP_PKEY* pkey = nullptr;
174
780
    if (!EVP_PKEY_keygen(ctx.get(), &pkey))
175
94
      return KeyGenJobStatus::FAILED;
176
177
686
    params->key = ManagedEVPPKey(EVPKeyPointer(pkey));
178
686
    return KeyGenJobStatus::OK;
179
  }
180
181
685
  static v8::Maybe<bool> EncodeKey(
182
      Environment* env,
183
      AdditionalParameters* params,
184
      v8::Local<v8::Value>* result) {
185
2055
    v8::Local<v8::Value> keys[2];
186
685
    if (params->key
187
685
            .ToEncodedPublicKey(env, params->public_key_encoding, &keys[0])
188

2050
            .IsNothing() ||
189
        params->key
190
680
            .ToEncodedPrivateKey(env, params->private_key_encoding, &keys[1])
191
1365
            .IsNothing()) {
192
5
      return v8::Nothing<bool>();
193
    }
194
680
    *result = v8::Array::New(env->isolate(), keys, arraysize(keys));
195
680
    return v8::Just(true);
196
  }
197
};
198
199
struct SecretKeyGenConfig final : public MemoryRetainer {
200
  size_t length;        // In bytes.
201
  ByteSource out;       // 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
785
  KeyPairGenConfig() = default;
238
3138
  ~KeyPairGenConfig() {
239
3138
    Mutex::ScopedLock priv_lock(*key.mutex());
240
  }
241
242
785
  explicit KeyPairGenConfig(KeyPairGenConfig&& other) noexcept
243
      : public_key_encoding(other.public_key_encoding),
244
        private_key_encoding(
245
            std::forward<PrivateKeyEncodingConfig>(
246
785
                other.private_key_encoding)),
247
785
        key(std::move(other.key)),
248
785
        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
256
  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