GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/crypto/crypto_keys.h Lines: 48 75 64.0 %
Date: 2020-12-12 04:11:07 Branches: 10 27 37.0 %

Line Branch Exec Source
1
#ifndef SRC_CRYPTO_CRYPTO_KEYS_H_
2
#define SRC_CRYPTO_CRYPTO_KEYS_H_
3
4
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6
#include "crypto/crypto_util.h"
7
#include "base_object.h"
8
#include "env.h"
9
#include "memory_tracker.h"
10
#include "node_buffer.h"
11
#include "node_worker.h"
12
#include "v8.h"
13
14
#include <openssl/evp.h>
15
16
#include <memory>
17
#include <string>
18
19
namespace node {
20
namespace crypto {
21
enum PKEncodingType {
22
  // RSAPublicKey / RSAPrivateKey according to PKCS#1.
23
  kKeyEncodingPKCS1,
24
  // PrivateKeyInfo or EncryptedPrivateKeyInfo according to PKCS#8.
25
  kKeyEncodingPKCS8,
26
  // SubjectPublicKeyInfo according to X.509.
27
  kKeyEncodingSPKI,
28
  // ECPrivateKey according to SEC1.
29
  kKeyEncodingSEC1
30
};
31
32
enum PKFormatType {
33
  kKeyFormatDER,
34
  kKeyFormatPEM
35
};
36
37
enum KeyType {
38
  kKeyTypeSecret,
39
  kKeyTypePublic,
40
  kKeyTypePrivate
41
};
42
43
enum KeyEncodingContext {
44
  kKeyContextInput,
45
  kKeyContextExport,
46
  kKeyContextGenerate
47
};
48
49
enum class ParseKeyResult {
50
  kParseKeyOk,
51
  kParseKeyNotRecognized,
52
  kParseKeyNeedPassphrase,
53
  kParseKeyFailed
54
};
55
56
2465
struct AsymmetricKeyEncodingConfig {
57
  bool output_key_object_ = false;
58
  PKFormatType format_ = kKeyFormatDER;
59
  v8::Maybe<PKEncodingType> type_ = v8::Nothing<PKEncodingType>();
60
};
61
62
using PublicKeyEncodingConfig = AsymmetricKeyEncodingConfig;
63
64
11659
struct PrivateKeyEncodingConfig : public AsymmetricKeyEncodingConfig {
65
  const EVP_CIPHER* cipher_;
66
  // The ByteSource alone is not enough to distinguish between "no passphrase"
67
  // and a zero-length passphrase (which can be a null pointer), therefore, we
68
  // use a NonCopyableMaybe.
69
  NonCopyableMaybe<ByteSource> passphrase_;
70
};
71
72
// This uses the built-in reference counter of OpenSSL to manage an EVP_PKEY
73
// which is slightly more efficient than using a shared pointer and easier to
74
// use.
75
11882
class ManagedEVPPKey : public MemoryRetainer {
76
 public:
77
1896
  ManagedEVPPKey() = default;
78
  explicit ManagedEVPPKey(EVPKeyPointer&& pkey);
79
  ManagedEVPPKey(const ManagedEVPPKey& that);
80
  ManagedEVPPKey& operator=(const ManagedEVPPKey& that);
81
82
  operator bool() const;
83
  EVP_PKEY* get() const;
84
85
  void MemoryInfo(MemoryTracker* tracker) const override;
86
  SET_MEMORY_INFO_NAME(ManagedEVPPKey)
87
  SET_SELF_SIZE(ManagedEVPPKey)
88
89
  static PublicKeyEncodingConfig GetPublicKeyEncodingFromJs(
90
      const v8::FunctionCallbackInfo<v8::Value>& args,
91
      unsigned int* offset,
92
      KeyEncodingContext context);
93
94
  static NonCopyableMaybe<PrivateKeyEncodingConfig> GetPrivateKeyEncodingFromJs(
95
      const v8::FunctionCallbackInfo<v8::Value>& args,
96
      unsigned int* offset,
97
      KeyEncodingContext context);
98
99
  static ManagedEVPPKey GetParsedKey(Environment* env,
100
                                     EVPKeyPointer&& pkey,
101
                                     ParseKeyResult ret,
102
                                     const char* default_msg);
103
104
  static ManagedEVPPKey GetPublicOrPrivateKeyFromJs(
105
    const v8::FunctionCallbackInfo<v8::Value>& args,
106
    unsigned int* offset);
107
108
  static ManagedEVPPKey GetPrivateKeyFromJs(
109
      const v8::FunctionCallbackInfo<v8::Value>& args,
110
      unsigned int* offset,
111
      bool allow_key_object);
112
113
  static v8::Maybe<bool> ToEncodedPublicKey(
114
      Environment* env,
115
      ManagedEVPPKey key,
116
      const PublicKeyEncodingConfig& config,
117
      v8::Local<v8::Value>* out);
118
119
  static v8::Maybe<bool> ToEncodedPrivateKey(
120
      Environment* env,
121
      ManagedEVPPKey key,
122
      const PrivateKeyEncodingConfig& config,
123
      v8::Local<v8::Value>* out);
124
125
 private:
126
  size_t size_of_private_key() const;
127
  size_t size_of_public_key() const;
128
129
  EVPKeyPointer pkey_;
130
};
131
132
// Objects of this class can safely be shared among threads.
133
5734
class KeyObjectData : public MemoryRetainer {
134
 public:
135
  static std::shared_ptr<KeyObjectData> CreateSecret(
136
      const ArrayBufferOrViewContents<char>& buf);
137
138
  static std::shared_ptr<KeyObjectData> CreateSecret(ByteSource key);
139
140
  static std::shared_ptr<KeyObjectData> CreateAsymmetric(
141
      KeyType type,
142
      const ManagedEVPPKey& pkey);
143
144
  KeyType GetKeyType() const;
145
146
  // These functions allow unprotected access to the raw key material and should
147
  // only be used to implement cryptographic operations requiring the key.
148
  ManagedEVPPKey GetAsymmetricKey() const;
149
  const char* GetSymmetricKey() const;
150
  size_t GetSymmetricKeySize() const;
151
152
  void MemoryInfo(MemoryTracker* tracker) const override;
153
  SET_MEMORY_INFO_NAME(KeyObjectData);
154
  SET_SELF_SIZE(KeyObjectData);
155
156
 private:
157
  explicit KeyObjectData(ByteSource symmetric_key);
158
159
  KeyObjectData(
160
      KeyType type,
161
      const ManagedEVPPKey& pkey);
162
163
  const KeyType key_type_;
164
  const ByteSource symmetric_key_;
165
  const unsigned int symmetric_key_len_;
166
  const ManagedEVPPKey asymmetric_key_;
167
};
168
169
5760
class KeyObjectHandle : public BaseObject {
170
 public:
171
  static v8::Local<v8::Function> Initialize(Environment* env);
172
173
  static v8::MaybeLocal<v8::Object> Create(Environment* env,
174
                                           std::shared_ptr<KeyObjectData> data);
175
176
  // TODO(tniessen): track the memory used by OpenSSL types
177
  SET_NO_MEMORY_INFO()
178
  SET_MEMORY_INFO_NAME(KeyObjectHandle)
179
  SET_SELF_SIZE(KeyObjectHandle)
180
181
  const std::shared_ptr<KeyObjectData>& Data();
182
183
 protected:
184
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
185
186
  static void Init(const v8::FunctionCallbackInfo<v8::Value>& args);
187
  static void InitECRaw(const v8::FunctionCallbackInfo<v8::Value>& args);
188
  static void InitJWK(const v8::FunctionCallbackInfo<v8::Value>& args);
189
  static void GetKeyDetail(const v8::FunctionCallbackInfo<v8::Value>& args);
190
191
  static void ExportJWK(const v8::FunctionCallbackInfo<v8::Value>& args);
192
193
  static void GetAsymmetricKeyType(
194
      const v8::FunctionCallbackInfo<v8::Value>& args);
195
  v8::Local<v8::Value> GetAsymmetricKeyType() const;
196
197
  static void GetSymmetricKeySize(
198
      const v8::FunctionCallbackInfo<v8::Value>& args);
199
200
  static void Export(const v8::FunctionCallbackInfo<v8::Value>& args);
201
202
  v8::MaybeLocal<v8::Value> ExportSecretKey() const;
203
  v8::MaybeLocal<v8::Value> ExportPublicKey(
204
      const PublicKeyEncodingConfig& config) const;
205
  v8::MaybeLocal<v8::Value> ExportPrivateKey(
206
      const PrivateKeyEncodingConfig& config) const;
207
208
  KeyObjectHandle(Environment* env,
209
                  v8::Local<v8::Object> wrap);
210
211
 private:
212
  std::shared_ptr<KeyObjectData> data_;
213
};
214
215
5750
class NativeKeyObject : public BaseObject {
216
 public:
217
  static void Initialize(Environment* env, v8::Local<v8::Object> target);
218
219
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
220
  static void CreateNativeKeyObjectClass(
221
      const v8::FunctionCallbackInfo<v8::Value>& args);
222
223
  SET_NO_MEMORY_INFO()
224
  SET_MEMORY_INFO_NAME(NativeKeyObject)
225
  SET_SELF_SIZE(NativeKeyObject)
226
227
22
  class KeyObjectTransferData : public worker::TransferData {
228
   public:
229
11
    explicit KeyObjectTransferData(const std::shared_ptr<KeyObjectData>& data)
230
11
        : data_(data) {}
231
232
    BaseObjectPtr<BaseObject> Deserialize(
233
        Environment* env,
234
        v8::Local<v8::Context> context,
235
        std::unique_ptr<worker::TransferData> self) override;
236
237
    SET_MEMORY_INFO_NAME(KeyObjectTransferData)
238
    SET_SELF_SIZE(KeyObjectTransferData)
239
    SET_NO_MEMORY_INFO()
240
241
   private:
242
    std::shared_ptr<KeyObjectData> data_;
243
  };
244
245
  BaseObject::TransferMode GetTransferMode() const override;
246
  std::unique_ptr<worker::TransferData> CloneForMessaging() const override;
247
248
 private:
249
2875
  NativeKeyObject(Environment* env,
250
                  v8::Local<v8::Object> wrap,
251
                  const std::shared_ptr<KeyObjectData>& handle_data)
252
2875
    : BaseObject(env, wrap),
253
2875
      handle_data_(handle_data) {
254
2875
    MakeWeak();
255
2875
  }
256
257
  std::shared_ptr<KeyObjectData> handle_data_;
258
};
259
260
enum WebCryptoKeyFormat {
261
  kWebCryptoKeyFormatRaw,
262
  kWebCryptoKeyFormatPKCS8,
263
  kWebCryptoKeyFormatSPKI,
264
  kWebCryptoKeyFormatJWK
265
};
266
267
enum class WebCryptoKeyExportStatus {
268
  OK,
269
  INVALID_KEY_TYPE,
270
  FAILED
271
};
272
273
template <typename KeyExportTraits>
274
448
class KeyExportJob final : public CryptoJob<KeyExportTraits> {
275
 public:
276
  using AdditionalParams = typename KeyExportTraits::AdditionalParameters;
277
278
224
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
279
224
    Environment* env = Environment::GetCurrent(args);
280
224
    CHECK(args.IsConstructCall());
281
282
224
    CryptoJobMode mode = GetCryptoJobMode(args[0]);
283
284
448
    CHECK(args[1]->IsUint32());  // Export Type
285
448
    CHECK(args[2]->IsObject());  // KeyObject
286
287
    WebCryptoKeyFormat format =
288
672
        static_cast<WebCryptoKeyFormat>(args[1].As<v8::Uint32>()->Value());
289
290
    KeyObjectHandle* key;
291
224
    ASSIGN_OR_RETURN_UNWRAP(&key, args[2]);
292
293
224
    CHECK_NOT_NULL(key);
294
295
448
    AdditionalParams params;
296
448
    if (KeyExportTraits::AdditionalConfig(args, 3, &params).IsNothing()) {
297
      // The KeyExportTraits::AdditionalConfig is responsible for
298
      // calling an appropriate THROW_CRYPTO_* variant reporting
299
      // whatever error caused initialization to fail.
300
      return;
301
    }
302
303
224
    new KeyExportJob<KeyExportTraits>(
304
        env,
305
448
        args.This(),
306
        mode,
307
        key->Data(),
308
        format,
309
        std::move(params));
310
  }
311
312
2624
  static void Initialize(
313
      Environment* env,
314
      v8::Local<v8::Object> target) {
315
2624
    CryptoJob<KeyExportTraits>::Initialize(New, env, target);
316
2624
  }
317
318
224
  KeyExportJob(
319
      Environment* env,
320
      v8::Local<v8::Object> object,
321
      CryptoJobMode mode,
322
      std::shared_ptr<KeyObjectData> key,
323
      WebCryptoKeyFormat format,
324
      AdditionalParams&& params)
325
      : CryptoJob<KeyExportTraits>(
326
            env,
327
            object,
328
            AsyncWrap::PROVIDER_KEYEXPORTREQUEST,
329
            mode,
330
224
            std::move(params)),
331
        key_(key),
332
224
        format_(format) {}
333
334
  WebCryptoKeyFormat format() const { return format_; }
335
336
224
  void DoThreadPoolWork() override {
337
448
    switch (KeyExportTraits::DoExport(
338
                key_,
339
                format_,
340
224
                *CryptoJob<KeyExportTraits>::params(),
341
                &out_)) {
342
      case WebCryptoKeyExportStatus::OK:
343
        // Success!
344
224
        break;
345
      case WebCryptoKeyExportStatus::INVALID_KEY_TYPE:
346
        // Fall through
347
        // TODO(@jasnell): Separate error for this
348
      case WebCryptoKeyExportStatus::FAILED: {
349
        CryptoErrorVector* errors = CryptoJob<KeyExportTraits>::errors();
350
        errors->Capture();
351
        if (errors->empty())
352
          errors->push_back("Key export failed.");
353
      }
354
    }
355
224
  }
356
357
224
  v8::Maybe<bool> ToResult(
358
      v8::Local<v8::Value>* err,
359
      v8::Local<v8::Value>* result) override {
360
224
    Environment* env = AsyncWrap::env();
361
224
    CryptoErrorVector* errors = CryptoJob<KeyExportTraits>::errors();
362
224
    if (out_.size() > 0) {
363
224
      CHECK(errors->empty());
364
448
      *err = v8::Undefined(env->isolate());
365
448
      *result = out_.ToArrayBuffer(env);
366
224
      return v8::Just(!result->IsEmpty());
367
    }
368
369
    if (errors->empty())
370
      errors->Capture();
371
    CHECK(!errors->empty());
372
    *result = v8::Undefined(env->isolate());
373
    return v8::Just(errors->ToException(env).ToLocal(err));
374
  }
375
376
  SET_SELF_SIZE(KeyExportJob)
377
  void MemoryInfo(MemoryTracker* tracker) const override {
378
    tracker->TrackFieldWithSize("out", out_.size());
379
    CryptoJob<KeyExportTraits>::MemoryInfo(tracker);
380
  }
381
382
 private:
383
  std::shared_ptr<KeyObjectData> key_;
384
  WebCryptoKeyFormat format_;
385
  ByteSource out_;
386
};
387
388
WebCryptoKeyExportStatus PKEY_SPKI_Export(
389
    KeyObjectData* key_data,
390
    ByteSource* out);
391
392
WebCryptoKeyExportStatus PKEY_PKCS8_Export(
393
    KeyObjectData* key_data,
394
    ByteSource* out);
395
396
namespace Keys {
397
void Initialize(Environment* env, v8::Local<v8::Object> target);
398
}  // namespace Keys
399
400
}  // namespace crypto
401
}  // namespace node
402
403
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
404
#endif  // SRC_CRYPTO_CRYPTO_KEYS_H_