GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_keys.h Lines: 45 80 56.2 %
Date: 2022-05-20 04:15:46 Branches: 10 30 33.3 %

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
  kKeyFormatJWK
36
};
37
38
enum KeyType {
39
  kKeyTypeSecret,
40
  kKeyTypePublic,
41
  kKeyTypePrivate
42
};
43
44
enum KeyEncodingContext {
45
  kKeyContextInput,
46
  kKeyContextExport,
47
  kKeyContextGenerate
48
};
49
50
enum class ParseKeyResult {
51
  kParseKeyOk,
52
  kParseKeyNotRecognized,
53
  kParseKeyNeedPassphrase,
54
  kParseKeyFailed
55
};
56
57
struct AsymmetricKeyEncodingConfig {
58
  bool output_key_object_ = false;
59
  PKFormatType format_ = kKeyFormatDER;
60
  v8::Maybe<PKEncodingType> type_ = v8::Nothing<PKEncodingType>();
61
};
62
63
using PublicKeyEncodingConfig = AsymmetricKeyEncodingConfig;
64
65
struct PrivateKeyEncodingConfig : public AsymmetricKeyEncodingConfig {
66
  const EVP_CIPHER* cipher_;
67
  // The ByteSource alone is not enough to distinguish between "no passphrase"
68
  // and a zero-length passphrase (which can be a null pointer), therefore, we
69
  // use a NonCopyableMaybe.
70
  NonCopyableMaybe<ByteSource> passphrase_;
71
};
72
73
// This uses the built-in reference counter of OpenSSL to manage an EVP_PKEY
74
// which is slightly more efficient than using a shared pointer and easier to
75
// use.
76
class ManagedEVPPKey : public MemoryRetainer {
77
 public:
78
8372
  ManagedEVPPKey() : mutex_(std::make_shared<Mutex>()) {}
79
  explicit ManagedEVPPKey(EVPKeyPointer&& pkey);
80
  ManagedEVPPKey(const ManagedEVPPKey& that);
81
  ManagedEVPPKey& operator=(const ManagedEVPPKey& that);
82
83
  operator bool() const;
84
  EVP_PKEY* get() const;
85
  Mutex* mutex() const;
86
87
  void MemoryInfo(MemoryTracker* tracker) const override;
88
  SET_MEMORY_INFO_NAME(ManagedEVPPKey)
89
  SET_SELF_SIZE(ManagedEVPPKey)
90
91
  static PublicKeyEncodingConfig GetPublicKeyEncodingFromJs(
92
      const v8::FunctionCallbackInfo<v8::Value>& args,
93
      unsigned int* offset,
94
      KeyEncodingContext context);
95
96
  static NonCopyableMaybe<PrivateKeyEncodingConfig> GetPrivateKeyEncodingFromJs(
97
      const v8::FunctionCallbackInfo<v8::Value>& args,
98
      unsigned int* offset,
99
      KeyEncodingContext context);
100
101
  static ManagedEVPPKey GetParsedKey(Environment* env,
102
                                     EVPKeyPointer&& pkey,
103
                                     ParseKeyResult ret,
104
                                     const char* default_msg);
105
106
  static ManagedEVPPKey GetPublicOrPrivateKeyFromJs(
107
    const v8::FunctionCallbackInfo<v8::Value>& args,
108
    unsigned int* offset);
109
110
  static ManagedEVPPKey GetPrivateKeyFromJs(
111
      const v8::FunctionCallbackInfo<v8::Value>& args,
112
      unsigned int* offset,
113
      bool allow_key_object);
114
115
  static v8::Maybe<bool> ToEncodedPublicKey(
116
      Environment* env,
117
      ManagedEVPPKey key,
118
      const PublicKeyEncodingConfig& config,
119
      v8::Local<v8::Value>* out);
120
121
  static v8::Maybe<bool> ToEncodedPrivateKey(
122
      Environment* env,
123
      ManagedEVPPKey key,
124
      const PrivateKeyEncodingConfig& config,
125
      v8::Local<v8::Value>* out);
126
127
 private:
128
  size_t size_of_private_key() const;
129
  size_t size_of_public_key() const;
130
131
  EVPKeyPointer pkey_;
132
  std::shared_ptr<Mutex> mutex_;
133
};
134
135
// Objects of this class can safely be shared among threads.
136
class KeyObjectData : public MemoryRetainer {
137
 public:
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
class KeyObjectHandle : public BaseObject {
170
 public:
171
  static v8::Local<v8::Function> Initialize(Environment* env);
172
  static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
173
174
  static v8::MaybeLocal<v8::Object> Create(Environment* env,
175
                                           std::shared_ptr<KeyObjectData> data);
176
177
  // TODO(tniessen): track the memory used by OpenSSL types
178
  SET_NO_MEMORY_INFO()
179
  SET_MEMORY_INFO_NAME(KeyObjectHandle)
180
  SET_SELF_SIZE(KeyObjectHandle)
181
182
  const std::shared_ptr<KeyObjectData>& Data();
183
184
 protected:
185
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
186
187
  static void Init(const v8::FunctionCallbackInfo<v8::Value>& args);
188
  static void InitECRaw(const v8::FunctionCallbackInfo<v8::Value>& args);
189
  static void InitEDRaw(const v8::FunctionCallbackInfo<v8::Value>& args);
190
  static void InitJWK(const v8::FunctionCallbackInfo<v8::Value>& args);
191
  static void GetKeyDetail(const v8::FunctionCallbackInfo<v8::Value>& args);
192
  static void Equals(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
  static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
222
223
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
224
  static void CreateNativeKeyObjectClass(
225
      const v8::FunctionCallbackInfo<v8::Value>& args);
226
227
  SET_NO_MEMORY_INFO()
228
  SET_MEMORY_INFO_NAME(NativeKeyObject)
229
  SET_SELF_SIZE(NativeKeyObject)
230
231
  class KeyObjectTransferData : public worker::TransferData {
232
   public:
233
11
    explicit KeyObjectTransferData(const std::shared_ptr<KeyObjectData>& data)
234
11
        : data_(data) {}
235
236
    BaseObjectPtr<BaseObject> Deserialize(
237
        Environment* env,
238
        v8::Local<v8::Context> context,
239
        std::unique_ptr<worker::TransferData> self) override;
240
241
    SET_MEMORY_INFO_NAME(KeyObjectTransferData)
242
    SET_SELF_SIZE(KeyObjectTransferData)
243
    SET_NO_MEMORY_INFO()
244
245
   private:
246
    std::shared_ptr<KeyObjectData> data_;
247
  };
248
249
  BaseObject::TransferMode GetTransferMode() const override;
250
  std::unique_ptr<worker::TransferData> CloneForMessaging() const override;
251
252
 private:
253
4893
  NativeKeyObject(Environment* env,
254
                  v8::Local<v8::Object> wrap,
255
                  const std::shared_ptr<KeyObjectData>& handle_data)
256
4893
    : BaseObject(env, wrap),
257
4893
      handle_data_(handle_data) {
258
4893
    MakeWeak();
259
4893
  }
260
261
  std::shared_ptr<KeyObjectData> handle_data_;
262
};
263
264
enum WebCryptoKeyFormat {
265
  kWebCryptoKeyFormatRaw,
266
  kWebCryptoKeyFormatPKCS8,
267
  kWebCryptoKeyFormatSPKI,
268
  kWebCryptoKeyFormatJWK
269
};
270
271
enum class WebCryptoKeyExportStatus {
272
  OK,
273
  INVALID_KEY_TYPE,
274
  FAILED
275
};
276
277
template <typename KeyExportTraits>
278
class KeyExportJob final : public CryptoJob<KeyExportTraits> {
279
 public:
280
  using AdditionalParams = typename KeyExportTraits::AdditionalParameters;
281
282
510
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
283
510
    Environment* env = Environment::GetCurrent(args);
284
510
    CHECK(args.IsConstructCall());
285
286
510
    CryptoJobMode mode = GetCryptoJobMode(args[0]);
287
288
510
    CHECK(args[1]->IsUint32());  // Export Type
289
510
    CHECK(args[2]->IsObject());  // KeyObject
290
291
    WebCryptoKeyFormat format =
292
1020
        static_cast<WebCryptoKeyFormat>(args[1].As<v8::Uint32>()->Value());
293
294
    KeyObjectHandle* key;
295
510
    ASSIGN_OR_RETURN_UNWRAP(&key, args[2]);
296
297
510
    CHECK_NOT_NULL(key);
298
299
510
    AdditionalParams params;
300
1020
    if (KeyExportTraits::AdditionalConfig(args, 3, &params).IsNothing()) {
301
      // The KeyExportTraits::AdditionalConfig is responsible for
302
      // calling an appropriate THROW_CRYPTO_* variant reporting
303
      // whatever error caused initialization to fail.
304
      return;
305
    }
306
307
1020
    new KeyExportJob<KeyExportTraits>(
308
        env,
309
1020
        args.This(),
310
        mode,
311
        key->Data(),
312
        format,
313
510
        std::move(params));
314
  }
315
316
3376
  static void Initialize(
317
      Environment* env,
318
      v8::Local<v8::Object> target) {
319
3376
    CryptoJob<KeyExportTraits>::Initialize(New, env, target);
320
3376
  }
321
322
20444
  static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
323
20444
    CryptoJob<KeyExportTraits>::RegisterExternalReferences(New, registry);
324
20444
  }
325
326
510
  KeyExportJob(
327
      Environment* env,
328
      v8::Local<v8::Object> object,
329
      CryptoJobMode mode,
330
      std::shared_ptr<KeyObjectData> key,
331
      WebCryptoKeyFormat format,
332
      AdditionalParams&& params)
333
      : CryptoJob<KeyExportTraits>(
334
            env,
335
            object,
336
            AsyncWrap::PROVIDER_KEYEXPORTREQUEST,
337
            mode,
338
510
            std::move(params)),
339
        key_(key),
340
510
        format_(format) {}
341
342
  WebCryptoKeyFormat format() const { return format_; }
343
344
510
  void DoThreadPoolWork() override {
345
    const WebCryptoKeyExportStatus status =
346
510
        KeyExportTraits::DoExport(
347
510
            key_,
348
            format_,
349
510
            *CryptoJob<KeyExportTraits>::params(),
350
            &out_);
351
510
    if (status == WebCryptoKeyExportStatus::OK) {
352
      // Success!
353
510
      return;
354
    }
355
    CryptoErrorStore* errors = CryptoJob<KeyExportTraits>::errors();
356
    errors->Capture();
357
    if (errors->Empty()) {
358
      switch (status) {
359
        case WebCryptoKeyExportStatus::OK:
360
          UNREACHABLE();
361
          break;
362
        case WebCryptoKeyExportStatus::INVALID_KEY_TYPE:
363
          errors->Insert(NodeCryptoError::INVALID_KEY_TYPE);
364
          break;
365
        case WebCryptoKeyExportStatus::FAILED:
366
          errors->Insert(NodeCryptoError::CIPHER_JOB_FAILED);
367
          break;
368
      }
369
    }
370
  }
371
372
510
  v8::Maybe<bool> ToResult(
373
      v8::Local<v8::Value>* err,
374
      v8::Local<v8::Value>* result) override {
375
510
    Environment* env = AsyncWrap::env();
376
510
    CryptoErrorStore* errors = CryptoJob<KeyExportTraits>::errors();
377
510
    if (out_.size() > 0) {
378
510
      CHECK(errors->Empty());
379
510
      *err = v8::Undefined(env->isolate());
380
1020
      *result = out_.ToArrayBuffer(env);
381
510
      return v8::Just(!result->IsEmpty());
382
    }
383
384
    if (errors->Empty())
385
      errors->Capture();
386
    CHECK(!errors->Empty());
387
    *result = v8::Undefined(env->isolate());
388
    return v8::Just(errors->ToException(env).ToLocal(err));
389
  }
390
391
  SET_SELF_SIZE(KeyExportJob)
392
  void MemoryInfo(MemoryTracker* tracker) const override {
393
    tracker->TrackFieldWithSize("out", out_.size());
394
    CryptoJob<KeyExportTraits>::MemoryInfo(tracker);
395
  }
396
397
 private:
398
  std::shared_ptr<KeyObjectData> key_;
399
  WebCryptoKeyFormat format_;
400
  ByteSource out_;
401
};
402
403
WebCryptoKeyExportStatus PKEY_SPKI_Export(
404
    KeyObjectData* key_data,
405
    ByteSource* out);
406
407
WebCryptoKeyExportStatus PKEY_PKCS8_Export(
408
    KeyObjectData* key_data,
409
    ByteSource* out);
410
411
namespace Keys {
412
void Initialize(Environment* env, v8::Local<v8::Object> target);
413
void RegisterExternalReferences(ExternalReferenceRegistry* registry);
414
}  // namespace Keys
415
416
}  // namespace crypto
417
}  // namespace node
418
419
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
420
#endif  // SRC_CRYPTO_CRYPTO_KEYS_H_