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: 3 73 4.1 %
Date: 2021-02-19 04:08:54 Branches: 0 27 0.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
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
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
class ManagedEVPPKey : public MemoryRetainer {
76
 public:
77
  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
  Mutex* mutex() const;
85
86
  void MemoryInfo(MemoryTracker* tracker) const override;
87
  SET_MEMORY_INFO_NAME(ManagedEVPPKey)
88
  SET_SELF_SIZE(ManagedEVPPKey)
89
90
  static PublicKeyEncodingConfig GetPublicKeyEncodingFromJs(
91
      const v8::FunctionCallbackInfo<v8::Value>& args,
92
      unsigned int* offset,
93
      KeyEncodingContext context);
94
95
  static NonCopyableMaybe<PrivateKeyEncodingConfig> GetPrivateKeyEncodingFromJs(
96
      const v8::FunctionCallbackInfo<v8::Value>& args,
97
      unsigned int* offset,
98
      KeyEncodingContext context);
99
100
  static ManagedEVPPKey GetParsedKey(Environment* env,
101
                                     EVPKeyPointer&& pkey,
102
                                     ParseKeyResult ret,
103
                                     const char* default_msg);
104
105
  static ManagedEVPPKey GetPublicOrPrivateKeyFromJs(
106
    const v8::FunctionCallbackInfo<v8::Value>& args,
107
    unsigned int* offset);
108
109
  static ManagedEVPPKey GetPrivateKeyFromJs(
110
      const v8::FunctionCallbackInfo<v8::Value>& args,
111
      unsigned int* offset,
112
      bool allow_key_object);
113
114
  static v8::Maybe<bool> ToEncodedPublicKey(
115
      Environment* env,
116
      ManagedEVPPKey key,
117
      const PublicKeyEncodingConfig& config,
118
      v8::Local<v8::Value>* out);
119
120
  static v8::Maybe<bool> ToEncodedPrivateKey(
121
      Environment* env,
122
      ManagedEVPPKey key,
123
      const PrivateKeyEncodingConfig& config,
124
      v8::Local<v8::Value>* out);
125
126
 private:
127
  size_t size_of_private_key() const;
128
  size_t size_of_public_key() const;
129
130
  EVPKeyPointer pkey_;
131
  std::shared_ptr<Mutex> mutex_;
132
};
133
134
// Objects of this class can safely be shared among threads.
135
class KeyObjectData : public MemoryRetainer {
136
 public:
137
  static std::shared_ptr<KeyObjectData> CreateSecret(
138
      const ArrayBufferOrViewContents<char>& buf);
139
140
  static std::shared_ptr<KeyObjectData> CreateSecret(ByteSource key);
141
142
  static std::shared_ptr<KeyObjectData> CreateAsymmetric(
143
      KeyType type,
144
      const ManagedEVPPKey& pkey);
145
146
  KeyType GetKeyType() const;
147
148
  // These functions allow unprotected access to the raw key material and should
149
  // only be used to implement cryptographic operations requiring the key.
150
  ManagedEVPPKey GetAsymmetricKey() const;
151
  const char* GetSymmetricKey() const;
152
  size_t GetSymmetricKeySize() const;
153
154
  void MemoryInfo(MemoryTracker* tracker) const override;
155
  SET_MEMORY_INFO_NAME(KeyObjectData);
156
  SET_SELF_SIZE(KeyObjectData);
157
158
 private:
159
  explicit KeyObjectData(ByteSource symmetric_key);
160
161
  KeyObjectData(
162
      KeyType type,
163
      const ManagedEVPPKey& pkey);
164
165
  const KeyType key_type_;
166
  const ByteSource symmetric_key_;
167
  const unsigned int symmetric_key_len_;
168
  const ManagedEVPPKey asymmetric_key_;
169
};
170
171
class KeyObjectHandle : public BaseObject {
172
 public:
173
  static v8::Local<v8::Function> Initialize(Environment* env);
174
175
  static v8::MaybeLocal<v8::Object> Create(Environment* env,
176
                                           std::shared_ptr<KeyObjectData> data);
177
178
  // TODO(tniessen): track the memory used by OpenSSL types
179
  SET_NO_MEMORY_INFO()
180
  SET_MEMORY_INFO_NAME(KeyObjectHandle)
181
  SET_SELF_SIZE(KeyObjectHandle)
182
183
  const std::shared_ptr<KeyObjectData>& Data();
184
185
 protected:
186
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
187
188
  static void Init(const v8::FunctionCallbackInfo<v8::Value>& args);
189
  static void InitECRaw(const v8::FunctionCallbackInfo<v8::Value>& args);
190
  static void InitEDRaw(const v8::FunctionCallbackInfo<v8::Value>& args);
191
  static void InitJWK(const v8::FunctionCallbackInfo<v8::Value>& args);
192
  static void GetKeyDetail(const v8::FunctionCallbackInfo<v8::Value>& args);
193
194
  static void ExportJWK(const v8::FunctionCallbackInfo<v8::Value>& args);
195
196
  static void GetAsymmetricKeyType(
197
      const v8::FunctionCallbackInfo<v8::Value>& args);
198
  v8::Local<v8::Value> GetAsymmetricKeyType() const;
199
200
  static void GetSymmetricKeySize(
201
      const v8::FunctionCallbackInfo<v8::Value>& args);
202
203
  static void Export(const v8::FunctionCallbackInfo<v8::Value>& args);
204
205
  v8::MaybeLocal<v8::Value> ExportSecretKey() const;
206
  v8::MaybeLocal<v8::Value> ExportPublicKey(
207
      const PublicKeyEncodingConfig& config) const;
208
  v8::MaybeLocal<v8::Value> ExportPrivateKey(
209
      const PrivateKeyEncodingConfig& config) const;
210
211
  KeyObjectHandle(Environment* env,
212
                  v8::Local<v8::Object> wrap);
213
214
 private:
215
  std::shared_ptr<KeyObjectData> data_;
216
};
217
218
class NativeKeyObject : public BaseObject {
219
 public:
220
  static void Initialize(Environment* env, v8::Local<v8::Object> target);
221
222
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
223
  static void CreateNativeKeyObjectClass(
224
      const v8::FunctionCallbackInfo<v8::Value>& args);
225
226
  SET_NO_MEMORY_INFO()
227
  SET_MEMORY_INFO_NAME(NativeKeyObject)
228
  SET_SELF_SIZE(NativeKeyObject)
229
230
  class KeyObjectTransferData : public worker::TransferData {
231
   public:
232
    explicit KeyObjectTransferData(const std::shared_ptr<KeyObjectData>& data)
233
        : data_(data) {}
234
235
    BaseObjectPtr<BaseObject> Deserialize(
236
        Environment* env,
237
        v8::Local<v8::Context> context,
238
        std::unique_ptr<worker::TransferData> self) override;
239
240
    SET_MEMORY_INFO_NAME(KeyObjectTransferData)
241
    SET_SELF_SIZE(KeyObjectTransferData)
242
    SET_NO_MEMORY_INFO()
243
244
   private:
245
    std::shared_ptr<KeyObjectData> data_;
246
  };
247
248
  BaseObject::TransferMode GetTransferMode() const override;
249
  std::unique_ptr<worker::TransferData> CloneForMessaging() const override;
250
251
 private:
252
  NativeKeyObject(Environment* env,
253
                  v8::Local<v8::Object> wrap,
254
                  const std::shared_ptr<KeyObjectData>& handle_data)
255
    : BaseObject(env, wrap),
256
      handle_data_(handle_data) {
257
    MakeWeak();
258
  }
259
260
  std::shared_ptr<KeyObjectData> handle_data_;
261
};
262
263
enum WebCryptoKeyFormat {
264
  kWebCryptoKeyFormatRaw,
265
  kWebCryptoKeyFormatPKCS8,
266
  kWebCryptoKeyFormatSPKI,
267
  kWebCryptoKeyFormatJWK
268
};
269
270
enum class WebCryptoKeyExportStatus {
271
  OK,
272
  INVALID_KEY_TYPE,
273
  FAILED
274
};
275
276
template <typename KeyExportTraits>
277
class KeyExportJob final : public CryptoJob<KeyExportTraits> {
278
 public:
279
  using AdditionalParams = typename KeyExportTraits::AdditionalParameters;
280
281
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
282
    Environment* env = Environment::GetCurrent(args);
283
    CHECK(args.IsConstructCall());
284
285
    CryptoJobMode mode = GetCryptoJobMode(args[0]);
286
287
    CHECK(args[1]->IsUint32());  // Export Type
288
    CHECK(args[2]->IsObject());  // KeyObject
289
290
    WebCryptoKeyFormat format =
291
        static_cast<WebCryptoKeyFormat>(args[1].As<v8::Uint32>()->Value());
292
293
    KeyObjectHandle* key;
294
    ASSIGN_OR_RETURN_UNWRAP(&key, args[2]);
295
296
    CHECK_NOT_NULL(key);
297
298
    AdditionalParams params;
299
    if (KeyExportTraits::AdditionalConfig(args, 3, &params).IsNothing()) {
300
      // The KeyExportTraits::AdditionalConfig is responsible for
301
      // calling an appropriate THROW_CRYPTO_* variant reporting
302
      // whatever error caused initialization to fail.
303
      return;
304
    }
305
306
    new KeyExportJob<KeyExportTraits>(
307
        env,
308
        args.This(),
309
        mode,
310
        key->Data(),
311
        format,
312
        std::move(params));
313
  }
314
315
8
  static void Initialize(
316
      Environment* env,
317
      v8::Local<v8::Object> target) {
318
8
    CryptoJob<KeyExportTraits>::Initialize(New, env, target);
319
8
  }
320
321
  KeyExportJob(
322
      Environment* env,
323
      v8::Local<v8::Object> object,
324
      CryptoJobMode mode,
325
      std::shared_ptr<KeyObjectData> key,
326
      WebCryptoKeyFormat format,
327
      AdditionalParams&& params)
328
      : CryptoJob<KeyExportTraits>(
329
            env,
330
            object,
331
            AsyncWrap::PROVIDER_KEYEXPORTREQUEST,
332
            mode,
333
            std::move(params)),
334
        key_(key),
335
        format_(format) {}
336
337
  WebCryptoKeyFormat format() const { return format_; }
338
339
  void DoThreadPoolWork() override {
340
    switch (KeyExportTraits::DoExport(
341
                key_,
342
                format_,
343
                *CryptoJob<KeyExportTraits>::params(),
344
                &out_)) {
345
      case WebCryptoKeyExportStatus::OK:
346
        // Success!
347
        break;
348
      case WebCryptoKeyExportStatus::INVALID_KEY_TYPE:
349
        // Fall through
350
        // TODO(@jasnell): Separate error for this
351
      case WebCryptoKeyExportStatus::FAILED: {
352
        CryptoErrorVector* errors = CryptoJob<KeyExportTraits>::errors();
353
        errors->Capture();
354
        if (errors->empty())
355
          errors->push_back("Key export failed.");
356
      }
357
    }
358
  }
359
360
  v8::Maybe<bool> ToResult(
361
      v8::Local<v8::Value>* err,
362
      v8::Local<v8::Value>* result) override {
363
    Environment* env = AsyncWrap::env();
364
    CryptoErrorVector* errors = CryptoJob<KeyExportTraits>::errors();
365
    if (out_.size() > 0) {
366
      CHECK(errors->empty());
367
      *err = v8::Undefined(env->isolate());
368
      *result = out_.ToArrayBuffer(env);
369
      return v8::Just(!result->IsEmpty());
370
    }
371
372
    if (errors->empty())
373
      errors->Capture();
374
    CHECK(!errors->empty());
375
    *result = v8::Undefined(env->isolate());
376
    return v8::Just(errors->ToException(env).ToLocal(err));
377
  }
378
379
  SET_SELF_SIZE(KeyExportJob)
380
  void MemoryInfo(MemoryTracker* tracker) const override {
381
    tracker->TrackFieldWithSize("out", out_.size());
382
    CryptoJob<KeyExportTraits>::MemoryInfo(tracker);
383
  }
384
385
 private:
386
  std::shared_ptr<KeyObjectData> key_;
387
  WebCryptoKeyFormat format_;
388
  ByteSource out_;
389
};
390
391
WebCryptoKeyExportStatus PKEY_SPKI_Export(
392
    KeyObjectData* key_data,
393
    ByteSource* out);
394
395
WebCryptoKeyExportStatus PKEY_PKCS8_Export(
396
    KeyObjectData* key_data,
397
    ByteSource* out);
398
399
namespace Keys {
400
void Initialize(Environment* env, v8::Local<v8::Object> target);
401
}  // namespace Keys
402
403
}  // namespace crypto
404
}  // namespace node
405
406
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
407
#endif  // SRC_CRYPTO_CRYPTO_KEYS_H_