GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_cipher.h Lines: 49 68 72.1 %
Date: 2022-08-14 04:19:53 Branches: 22 40 55.0 %

Line Branch Exec Source
1
#ifndef SRC_CRYPTO_CRYPTO_CIPHER_H_
2
#define SRC_CRYPTO_CRYPTO_CIPHER_H_
3
4
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6
#include "crypto/crypto_keys.h"
7
#include "crypto/crypto_util.h"
8
#include "base_object.h"
9
#include "env.h"
10
#include "memory_tracker.h"
11
#include "v8.h"
12
13
#include <string>
14
15
namespace node {
16
namespace crypto {
17
class CipherBase : public BaseObject {
18
 public:
19
  static void GetSSLCiphers(const v8::FunctionCallbackInfo<v8::Value>& args);
20
  static void GetCiphers(const v8::FunctionCallbackInfo<v8::Value>& args);
21
22
  static void Initialize(Environment* env, v8::Local<v8::Object> target);
23
  static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
24
25
  void MemoryInfo(MemoryTracker* tracker) const override;
26
  SET_MEMORY_INFO_NAME(CipherBase)
27
  SET_SELF_SIZE(CipherBase)
28
29
 protected:
30
  enum CipherKind {
31
    kCipher,
32
    kDecipher
33
  };
34
  enum UpdateResult {
35
    kSuccess,
36
    kErrorMessageSize,
37
    kErrorState
38
  };
39
  enum AuthTagState {
40
    kAuthTagUnknown,
41
    kAuthTagKnown,
42
    kAuthTagPassedToOpenSSL
43
  };
44
  static const unsigned kNoAuthTagLength = static_cast<unsigned>(-1);
45
46
  void CommonInit(const char* cipher_type,
47
                  const EVP_CIPHER* cipher,
48
                  const unsigned char* key,
49
                  int key_len,
50
                  const unsigned char* iv,
51
                  int iv_len,
52
                  unsigned int auth_tag_len);
53
  void Init(const char* cipher_type,
54
            const ArrayBufferOrViewContents<unsigned char>& key_buf,
55
            unsigned int auth_tag_len);
56
  void InitIv(const char* cipher_type,
57
              const ByteSource& key_buf,
58
              const ArrayBufferOrViewContents<unsigned char>& iv_buf,
59
              unsigned int auth_tag_len);
60
  bool InitAuthenticated(const char* cipher_type, int iv_len,
61
                         unsigned int auth_tag_len);
62
  bool CheckCCMMessageLength(int message_len);
63
  UpdateResult Update(const char* data, size_t len,
64
                      std::unique_ptr<v8::BackingStore>* out);
65
  bool Final(std::unique_ptr<v8::BackingStore>* out);
66
  bool SetAutoPadding(bool auto_padding);
67
68
  bool IsAuthenticatedMode() const;
69
  bool SetAAD(
70
      const ArrayBufferOrViewContents<unsigned char>& data,
71
      int plaintext_len);
72
  bool MaybePassAuthTagToOpenSSL();
73
74
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
75
  static void Init(const v8::FunctionCallbackInfo<v8::Value>& args);
76
  static void InitIv(const v8::FunctionCallbackInfo<v8::Value>& args);
77
  static void Update(const v8::FunctionCallbackInfo<v8::Value>& args);
78
  static void Final(const v8::FunctionCallbackInfo<v8::Value>& args);
79
  static void SetAutoPadding(const v8::FunctionCallbackInfo<v8::Value>& args);
80
81
  static void GetAuthTag(const v8::FunctionCallbackInfo<v8::Value>& args);
82
  static void SetAuthTag(const v8::FunctionCallbackInfo<v8::Value>& args);
83
  static void SetAAD(const v8::FunctionCallbackInfo<v8::Value>& args);
84
85
  CipherBase(Environment* env, v8::Local<v8::Object> wrap, CipherKind kind);
86
87
 private:
88
  DeleteFnPtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free> ctx_;
89
  const CipherKind kind_;
90
  AuthTagState auth_tag_state_;
91
  unsigned int auth_tag_len_;
92
  char auth_tag_[EVP_GCM_TLS_TAG_LEN];
93
  bool pending_auth_failed_;
94
  int max_message_size_;
95
};
96
97
class PublicKeyCipher {
98
 public:
99
  typedef int (*EVP_PKEY_cipher_init_t)(EVP_PKEY_CTX* ctx);
100
  typedef int (*EVP_PKEY_cipher_t)(EVP_PKEY_CTX* ctx,
101
                                   unsigned char* out, size_t* outlen,
102
                                   const unsigned char* in, size_t inlen);
103
104
  enum Operation {
105
    kPublic,
106
    kPrivate
107
  };
108
109
  template <Operation operation,
110
            EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
111
            EVP_PKEY_cipher_t EVP_PKEY_cipher>
112
  static bool Cipher(Environment* env,
113
                     const ManagedEVPPKey& pkey,
114
                     int padding,
115
                     const EVP_MD* digest,
116
                     const ArrayBufferOrViewContents<unsigned char>& oaep_label,
117
                     const ArrayBufferOrViewContents<unsigned char>& data,
118
                     std::unique_ptr<v8::BackingStore>* out);
119
120
  template <Operation operation,
121
            EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
122
            EVP_PKEY_cipher_t EVP_PKEY_cipher>
123
  static void Cipher(const v8::FunctionCallbackInfo<v8::Value>& args);
124
};
125
126
enum WebCryptoCipherMode {
127
  kWebCryptoCipherEncrypt,
128
  kWebCryptoCipherDecrypt
129
};
130
131
enum class WebCryptoCipherStatus {
132
  OK,
133
  INVALID_KEY_TYPE,
134
  FAILED
135
};
136
137
// CipherJob is a base implementation class for implementations of
138
// one-shot sync and async ciphers. It has been added primarily to
139
// support the AES and RSA ciphers underlying the WebCrypt API.
140
//
141
// See the crypto_aes and crypto_rsa headers for examples of how to
142
// use CipherJob.
143
template <typename CipherTraits>
144
class CipherJob final : public CryptoJob<CipherTraits> {
145
 public:
146
  using AdditionalParams = typename CipherTraits::AdditionalParameters;
147
148
1394
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
149
1394
    Environment* env = Environment::GetCurrent(args);
150
1394
    CHECK(args.IsConstructCall());
151
152
1394
    CryptoJobMode mode = GetCryptoJobMode(args[0]);
153
154
1394
    CHECK(args[1]->IsUint32());  // Cipher Mode
155
156
2788
    uint32_t cmode = args[1].As<v8::Uint32>()->Value();
157
1394
    CHECK_LE(cmode, WebCryptoCipherMode::kWebCryptoCipherDecrypt);
158
1394
    WebCryptoCipherMode cipher_mode = static_cast<WebCryptoCipherMode>(cmode);
159
160
1394
    CHECK(args[2]->IsObject());  // KeyObject
161
    KeyObjectHandle* key;
162
1394
    ASSIGN_OR_RETURN_UNWRAP(&key, args[2]);
163
1394
    CHECK_NOT_NULL(key);
164
165
1394
    ArrayBufferOrViewContents<char> data(args[3]);  // data to operate on
166
1394
    if (!data.CheckSizeInt32())
167
      return THROW_ERR_OUT_OF_RANGE(env, "data is too large");
168
169
1394
    AdditionalParams params;
170
2788
    if (CipherTraits::AdditionalConfig(mode, args, 4, cipher_mode, &params)
171
            .IsNothing()) {
172
      // The CipherTraits::AdditionalConfig is responsible for
173
      // calling an appropriate THROW_CRYPTO_* variant reporting
174
      // whatever error caused initialization to fail.
175
      return;
176
    }
177
178
1394
    new CipherJob<CipherTraits>(
179
        env,
180
1394
        args.This(),
181
        mode,
182
        key,
183
        cipher_mode,
184
        data,
185
1394
        std::move(params));
186
  }
187
188
1524
  static void Initialize(
189
      Environment* env,
190
      v8::Local<v8::Object> target) {
191
1524
    CryptoJob<CipherTraits>::Initialize(New, env, target);
192
1524
  }
193
194
10518
  static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
195
10518
    CryptoJob<CipherTraits>::RegisterExternalReferences(New, registry);
196
10518
  }
197
198
1394
  CipherJob(
199
      Environment* env,
200
      v8::Local<v8::Object> object,
201
      CryptoJobMode mode,
202
      KeyObjectHandle* key,
203
      WebCryptoCipherMode cipher_mode,
204
      const ArrayBufferOrViewContents<char>& data,
205
      AdditionalParams&& params)
206
      : CryptoJob<CipherTraits>(
207
            env,
208
            object,
209
            AsyncWrap::PROVIDER_CIPHERREQUEST,
210
            mode,
211
1394
            std::move(params)),
212
        key_(key->Data()),
213
        cipher_mode_(cipher_mode),
214
        in_(mode == kCryptoJobAsync
215
            ? data.ToCopy()
216
1394
            : data.ToByteSource()) {}
217
218
1394
  std::shared_ptr<KeyObjectData> key() const { return key_; }
219
220
  WebCryptoCipherMode cipher_mode() const { return cipher_mode_; }
221
222
1394
  void DoThreadPoolWork() override {
223
    const WebCryptoCipherStatus status =
224
1394
        CipherTraits::DoCipher(
225
            AsyncWrap::env(),
226
            key(),
227
            cipher_mode_,
228
1394
            *CryptoJob<CipherTraits>::params(),
229
1394
            in_,
230
            &out_);
231
1394
    if (status == WebCryptoCipherStatus::OK) {
232
      // Success!
233
1355
      return;
234
    }
235
39
    CryptoErrorStore* errors = CryptoJob<CipherTraits>::errors();
236
39
    errors->Capture();
237
39
    if (errors->Empty()) {
238
      switch (status) {
239
        case WebCryptoCipherStatus::OK:
240
          UNREACHABLE();
241
          break;
242
        case WebCryptoCipherStatus::INVALID_KEY_TYPE:
243
          errors->Insert(NodeCryptoError::INVALID_KEY_TYPE);
244
          break;
245
        case WebCryptoCipherStatus::FAILED:
246
          errors->Insert(NodeCryptoError::CIPHER_JOB_FAILED);
247
          break;
248
      }
249
    }
250
  }
251
252
1394
  v8::Maybe<bool> ToResult(
253
      v8::Local<v8::Value>* err,
254
      v8::Local<v8::Value>* result) override {
255
1394
    Environment* env = AsyncWrap::env();
256
1394
    CryptoErrorStore* errors = CryptoJob<CipherTraits>::errors();
257
258
1394
    if (errors->Empty())
259
1355
      errors->Capture();
260
261

1394
    if (out_.size() > 0 || errors->Empty()) {
262
1355
      CHECK(errors->Empty());
263
1355
      *err = v8::Undefined(env->isolate());
264
2710
      *result = out_.ToArrayBuffer(env);
265
1355
      return v8::Just(!result->IsEmpty());
266
    }
267
268
78
    *result = v8::Undefined(env->isolate());
269
78
    return v8::Just(errors->ToException(env).ToLocal(err));
270
  }
271
272
  SET_SELF_SIZE(CipherJob)
273
  void MemoryInfo(MemoryTracker* tracker) const override {
274
    if (CryptoJob<CipherTraits>::mode() == kCryptoJobAsync)
275
      tracker->TrackFieldWithSize("in", in_.size());
276
    tracker->TrackFieldWithSize("out", out_.size());
277
    CryptoJob<CipherTraits>::MemoryInfo(tracker);
278
  }
279
280
 private:
281
  std::shared_ptr<KeyObjectData> key_;
282
  WebCryptoCipherMode cipher_mode_;
283
  ByteSource in_;
284
  ByteSource out_;
285
};
286
287
}  // namespace crypto
288
}  // namespace node
289
290
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
291
#endif  // SRC_CRYPTO_CRYPTO_CIPHER_H_