GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_cipher.h Lines: 46 65 70.8 %
Date: 2021-09-27 04:13:02 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 "allocated_buffer-inl.h"
9
#include "base_object.h"
10
#include "env.h"
11
#include "memory_tracker.h"
12
#include "v8.h"
13
14
#include <string>
15
16
namespace node {
17
namespace crypto {
18
class CipherBase : public BaseObject {
19
 public:
20
  static void GetSSLCiphers(const v8::FunctionCallbackInfo<v8::Value>& args);
21
  static void GetCiphers(const v8::FunctionCallbackInfo<v8::Value>& args);
22
23
  static void Initialize(Environment* env, v8::Local<v8::Object> target);
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, AllocatedBuffer* out);
64
  bool Final(AllocatedBuffer* out);
65
  bool SetAutoPadding(bool auto_padding);
66
67
  bool IsAuthenticatedMode() const;
68
  bool SetAAD(
69
      const ArrayBufferOrViewContents<unsigned char>& data,
70
      int plaintext_len);
71
  bool MaybePassAuthTagToOpenSSL();
72
73
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
74
  static void Init(const v8::FunctionCallbackInfo<v8::Value>& args);
75
  static void InitIv(const v8::FunctionCallbackInfo<v8::Value>& args);
76
  static void Update(const v8::FunctionCallbackInfo<v8::Value>& args);
77
  static void Final(const v8::FunctionCallbackInfo<v8::Value>& args);
78
  static void SetAutoPadding(const v8::FunctionCallbackInfo<v8::Value>& args);
79
80
  static void GetAuthTag(const v8::FunctionCallbackInfo<v8::Value>& args);
81
  static void SetAuthTag(const v8::FunctionCallbackInfo<v8::Value>& args);
82
  static void SetAAD(const v8::FunctionCallbackInfo<v8::Value>& args);
83
84
  CipherBase(Environment* env, v8::Local<v8::Object> wrap, CipherKind kind);
85
86
 private:
87
  DeleteFnPtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free> ctx_;
88
  const CipherKind kind_;
89
  AuthTagState auth_tag_state_;
90
  unsigned int auth_tag_len_;
91
  char auth_tag_[EVP_GCM_TLS_TAG_LEN];
92
  bool pending_auth_failed_;
93
  int max_message_size_;
94
};
95
96
class PublicKeyCipher {
97
 public:
98
  typedef int (*EVP_PKEY_cipher_init_t)(EVP_PKEY_CTX* ctx);
99
  typedef int (*EVP_PKEY_cipher_t)(EVP_PKEY_CTX* ctx,
100
                                   unsigned char* out, size_t* outlen,
101
                                   const unsigned char* in, size_t inlen);
102
103
  enum Operation {
104
    kPublic,
105
    kPrivate
106
  };
107
108
  template <Operation operation,
109
            EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
110
            EVP_PKEY_cipher_t EVP_PKEY_cipher>
111
  static bool Cipher(Environment* env,
112
                     const ManagedEVPPKey& pkey,
113
                     int padding,
114
                     const EVP_MD* digest,
115
                     const ArrayBufferOrViewContents<unsigned char>& oaep_label,
116
                     const ArrayBufferOrViewContents<unsigned char>& data,
117
                     AllocatedBuffer* out);
118
119
  template <Operation operation,
120
            EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
121
            EVP_PKEY_cipher_t EVP_PKEY_cipher>
122
  static void Cipher(const v8::FunctionCallbackInfo<v8::Value>& args);
123
};
124
125
enum WebCryptoCipherMode {
126
  kWebCryptoCipherEncrypt,
127
  kWebCryptoCipherDecrypt
128
};
129
130
enum class WebCryptoCipherStatus {
131
  OK,
132
  INVALID_KEY_TYPE,
133
  FAILED
134
};
135
136
// CipherJob is a base implementation class for implementations of
137
// one-shot sync and async ciphers. It has been added primarily to
138
// support the AES and RSA ciphers underlying the WebCrypt API.
139
//
140
// See the crypto_aes and crypto_rsa headers for examples of how to
141
// use CipherJob.
142
template <typename CipherTraits>
143
class CipherJob final : public CryptoJob<CipherTraits> {
144
 public:
145
  using AdditionalParams = typename CipherTraits::AdditionalParameters;
146
147
1394
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
148
1394
    Environment* env = Environment::GetCurrent(args);
149
1394
    CHECK(args.IsConstructCall());
150
151
1394
    CryptoJobMode mode = GetCryptoJobMode(args[0]);
152
153
1394
    CHECK(args[1]->IsUint32());  // Cipher Mode
154
155
2788
    uint32_t cmode = args[1].As<v8::Uint32>()->Value();
156
1394
    CHECK_LE(cmode, WebCryptoCipherMode::kWebCryptoCipherDecrypt);
157
1394
    WebCryptoCipherMode cipher_mode = static_cast<WebCryptoCipherMode>(cmode);
158
159
1394
    CHECK(args[2]->IsObject());  // KeyObject
160
    KeyObjectHandle* key;
161
1394
    ASSIGN_OR_RETURN_UNWRAP(&key, args[2]);
162
1394
    CHECK_NOT_NULL(key);
163
164
1394
    ArrayBufferOrViewContents<char> data(args[3]);  // data to operate on
165
1394
    if (!data.CheckSizeInt32())
166
      return THROW_ERR_OUT_OF_RANGE(env, "data is too large");
167
168
1394
    AdditionalParams params;
169
2788
    if (CipherTraits::AdditionalConfig(mode, args, 4, cipher_mode, &params)
170
            .IsNothing()) {
171
      // The CipherTraits::AdditionalConfig is responsible for
172
      // calling an appropriate THROW_CRYPTO_* variant reporting
173
      // whatever error caused initialization to fail.
174
      return;
175
    }
176
177
1394
    new CipherJob<CipherTraits>(
178
        env,
179
1394
        args.This(),
180
        mode,
181
        key,
182
        cipher_mode,
183
        data,
184
1394
        std::move(params));
185
  }
186
187
8552
  static void Initialize(
188
      Environment* env,
189
      v8::Local<v8::Object> target) {
190
8552
    CryptoJob<CipherTraits>::Initialize(New, env, target);
191
8552
  }
192
193
1394
  CipherJob(
194
      Environment* env,
195
      v8::Local<v8::Object> object,
196
      CryptoJobMode mode,
197
      KeyObjectHandle* key,
198
      WebCryptoCipherMode cipher_mode,
199
      const ArrayBufferOrViewContents<char>& data,
200
      AdditionalParams&& params)
201
      : CryptoJob<CipherTraits>(
202
            env,
203
            object,
204
            AsyncWrap::PROVIDER_CIPHERREQUEST,
205
            mode,
206
1394
            std::move(params)),
207
        key_(key->Data()),
208
        cipher_mode_(cipher_mode),
209
        in_(mode == kCryptoJobAsync
210
            ? data.ToCopy()
211
1394
            : data.ToByteSource()) {}
212
213
1394
  std::shared_ptr<KeyObjectData> key() const { return key_; }
214
215
  WebCryptoCipherMode cipher_mode() const { return cipher_mode_; }
216
217
1394
  void DoThreadPoolWork() override {
218
    const WebCryptoCipherStatus status =
219
1394
        CipherTraits::DoCipher(
220
            AsyncWrap::env(),
221
            key(),
222
            cipher_mode_,
223
1394
            *CryptoJob<CipherTraits>::params(),
224
1394
            in_,
225
            &out_);
226
1394
    if (status == WebCryptoCipherStatus::OK) {
227
      // Success!
228
1355
      return;
229
    }
230
39
    CryptoErrorStore* errors = CryptoJob<CipherTraits>::errors();
231
39
    errors->Capture();
232
39
    if (errors->Empty()) {
233
      switch (status) {
234
        case WebCryptoCipherStatus::OK:
235
          UNREACHABLE();
236
          break;
237
        case WebCryptoCipherStatus::INVALID_KEY_TYPE:
238
          errors->Insert(NodeCryptoError::INVALID_KEY_TYPE);
239
          break;
240
        case WebCryptoCipherStatus::FAILED:
241
          errors->Insert(NodeCryptoError::CIPHER_JOB_FAILED);
242
          break;
243
      }
244
    }
245
  }
246
247
1394
  v8::Maybe<bool> ToResult(
248
      v8::Local<v8::Value>* err,
249
      v8::Local<v8::Value>* result) override {
250
1394
    Environment* env = AsyncWrap::env();
251
1394
    CryptoErrorStore* errors = CryptoJob<CipherTraits>::errors();
252
253
1394
    if (errors->Empty())
254
1355
      errors->Capture();
255
256

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