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_hmac.cc Lines: 118 145 81.4 %
Date: 2020-11-20 19:51:53 Branches: 44 83 53.0 %

Line Branch Exec Source
1
#include "crypto/crypto_hmac.h"
2
#include "crypto/crypto_keys.h"
3
#include "crypto/crypto_sig.h"
4
#include "crypto/crypto_util.h"
5
#include "allocated_buffer-inl.h"
6
#include "async_wrap-inl.h"
7
#include "base_object-inl.h"
8
#include "env-inl.h"
9
#include "memory_tracker-inl.h"
10
#include "node_buffer.h"
11
#include "string_bytes.h"
12
#include "threadpoolwork-inl.h"
13
#include "v8.h"
14
15
namespace node {
16
17
using v8::FunctionCallbackInfo;
18
using v8::FunctionTemplate;
19
using v8::HandleScope;
20
using v8::Just;
21
using v8::Local;
22
using v8::Maybe;
23
using v8::MaybeLocal;
24
using v8::Nothing;
25
using v8::Object;
26
using v8::Uint32;
27
using v8::Value;
28
29
namespace crypto {
30
164
Hmac::Hmac(Environment* env, Local<Object> wrap)
31
    : BaseObject(env, wrap),
32
164
      ctx_(nullptr) {
33
164
  MakeWeak();
34
164
}
35
36
void Hmac::MemoryInfo(MemoryTracker* tracker) const {
37
  tracker->TrackFieldWithSize("context", ctx_ ? kSizeOf_HMAC_CTX : 0);
38
}
39
40
653
void Hmac::Initialize(Environment* env, Local<Object> target) {
41
653
  Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
42
43
1962
  t->InstanceTemplate()->SetInternalFieldCount(
44
654
      Hmac::kInternalFieldCount);
45
1308
  t->Inherit(BaseObject::GetConstructorTemplate(env));
46
47
654
  env->SetProtoMethod(t, "init", HmacInit);
48
654
  env->SetProtoMethod(t, "update", HmacUpdate);
49
654
  env->SetProtoMethod(t, "digest", HmacDigest);
50
51
1308
  target->Set(env->context(),
52
              FIXED_ONE_BYTE_STRING(env->isolate(), "Hmac"),
53
3924
              t->GetFunction(env->context()).ToLocalChecked()).Check();
54
55
654
  HmacJob::Initialize(env, target);
56
654
}
57
58
164
void Hmac::New(const FunctionCallbackInfo<Value>& args) {
59
164
  Environment* env = Environment::GetCurrent(args);
60
164
  new Hmac(env, args.This());
61
164
}
62
63
164
void Hmac::HmacInit(const char* hash_type, const char* key, int key_len) {
64
327
  HandleScope scope(env()->isolate());
65
66
164
  const EVP_MD* md = EVP_get_digestbyname(hash_type);
67
164
  if (md == nullptr)
68
1
    return THROW_ERR_CRYPTO_INVALID_DIGEST(env());
69
163
  if (key_len == 0) {
70
6
    key = "";
71
  }
72
163
  ctx_.reset(HMAC_CTX_new());
73

163
  if (!ctx_ || !HMAC_Init_ex(ctx_.get(), key, key_len, md, nullptr)) {
74
    ctx_.reset();
75
    return ThrowCryptoError(env(), ERR_get_error());
76
  }
77
}
78
79
164
void Hmac::HmacInit(const FunctionCallbackInfo<Value>& args) {
80
  Hmac* hmac;
81
164
  ASSIGN_OR_RETURN_UNWRAP(&hmac, args.Holder());
82
164
  Environment* env = hmac->env();
83
84
328
  const node::Utf8Value hash_type(env->isolate(), args[0]);
85
328
  ByteSource key = ByteSource::FromSecretKeyBytes(env, args[1]);
86
164
  hmac->HmacInit(*hash_type, key.get(), key.size());
87
}
88
89
162
bool Hmac::HmacUpdate(const char* data, size_t len) {
90

162
  return ctx_ && HMAC_Update(ctx_.get(),
91
                             reinterpret_cast<const unsigned char*>(data),
92
324
                             len) == 1;
93
}
94
95
162
void Hmac::HmacUpdate(const FunctionCallbackInfo<Value>& args) {
96
324
  Decode<Hmac>(args, [](Hmac* hmac, const FunctionCallbackInfo<Value>& args,
97
486
                        const char* data, size_t size) {
98
162
    Environment* env = Environment::GetCurrent(args);
99
162
    if (UNLIKELY(size > INT_MAX))
100
      return THROW_ERR_OUT_OF_RANGE(env, "data is too long");
101
162
    bool r = hmac->HmacUpdate(data, size);
102
486
    args.GetReturnValue().Set(r);
103
486
  });
104
162
}
105
106
157
void Hmac::HmacDigest(const FunctionCallbackInfo<Value>& args) {
107
157
  Environment* env = Environment::GetCurrent(args);
108
109
  Hmac* hmac;
110
157
  ASSIGN_OR_RETURN_UNWRAP(&hmac, args.Holder());
111
112
157
  enum encoding encoding = BUFFER;
113
157
  if (args.Length() >= 1) {
114
129
    encoding = ParseEncoding(env->isolate(), args[0], BUFFER);
115
  }
116
117
  unsigned char md_value[EVP_MAX_MD_SIZE];
118
157
  unsigned int md_len = 0;
119
120
157
  if (hmac->ctx_) {
121
157
    HMAC_Final(hmac->ctx_.get(), md_value, &md_len);
122
157
    hmac->ctx_.reset();
123
  }
124
125
  Local<Value> error;
126
  MaybeLocal<Value> rc =
127
      StringBytes::Encode(env->isolate(),
128
                          reinterpret_cast<const char*>(md_value),
129
                          md_len,
130
                          encoding,
131
157
                          &error);
132
157
  if (rc.IsEmpty()) {
133
    CHECK(!error.IsEmpty());
134
    env->isolate()->ThrowException(error);
135
    return;
136
  }
137
314
  args.GetReturnValue().Set(rc.FromMaybe(Local<Value>()));
138
}
139
140
44
HmacConfig::HmacConfig(HmacConfig&& other) noexcept
141
44
    : job_mode(other.job_mode),
142
44
      mode(other.mode),
143
44
      key(std::move(other.key)),
144
44
      data(std::move(other.data)),
145
44
      signature(std::move(other.signature)),
146
264
      digest(other.digest) {}
147
148
HmacConfig& HmacConfig::operator=(HmacConfig&& other) noexcept {
149
  if (&other == this) return *this;
150
  this->~HmacConfig();
151
  return *new (this) HmacConfig(std::move(other));
152
}
153
154
void HmacConfig::MemoryInfo(MemoryTracker* tracker) const {
155
  tracker->TrackField("key", key.get());
156
  // If the job is sync, then the HmacConfig does not own the data
157
  if (job_mode == kCryptoJobAsync) {
158
    tracker->TrackFieldWithSize("data", data.size());
159
    tracker->TrackFieldWithSize("signature", signature.size());
160
  }
161
}
162
163
44
Maybe<bool> HmacTraits::AdditionalConfig(
164
    CryptoJobMode mode,
165
    const FunctionCallbackInfo<Value>& args,
166
    unsigned int offset,
167
    HmacConfig* params) {
168
44
  Environment* env = Environment::GetCurrent(args);
169
170
44
  params->job_mode = mode;
171
172
132
  CHECK(args[offset]->IsUint32());  // SignConfiguration::Mode
173
44
  params->mode =
174
220
    static_cast<SignConfiguration::Mode>(args[offset].As<Uint32>()->Value());
175
176
176
  CHECK(args[offset + 1]->IsString());  // Hash
177
132
  CHECK(args[offset + 2]->IsObject());  // Key
178
179
132
  Utf8Value digest(env->isolate(), args[offset + 1]);
180
44
  params->digest = EVP_get_digestbyname(*digest);
181
44
  if (params->digest == nullptr) {
182
    THROW_ERR_CRYPTO_INVALID_DIGEST(env);
183
    return Nothing<bool>();
184
  }
185
186
  KeyObjectHandle* key;
187
88
  ASSIGN_OR_RETURN_UNWRAP(&key, args[offset + 2], Nothing<bool>());
188
44
  params->key = key->Data();
189
190
132
  ArrayBufferOrViewContents<char> data(args[offset + 3]);
191
44
  if (UNLIKELY(!data.CheckSizeInt32())) {
192
    THROW_ERR_OUT_OF_RANGE(env, "data is too big");
193
    return Nothing<bool>();
194
  }
195
  params->data = mode == kCryptoJobAsync
196
88
      ? data.ToCopy()
197
44
      : data.ToByteSource();
198
199
176
  if (!args[offset + 4]->IsUndefined()) {
200
99
    ArrayBufferOrViewContents<char> signature(args[offset + 4]);
201
33
    if (UNLIKELY(!signature.CheckSizeInt32())) {
202
      THROW_ERR_OUT_OF_RANGE(env, "signature is too big");
203
      return Nothing<bool>();
204
    }
205
    params->signature = mode == kCryptoJobAsync
206

66
        ? signature.ToCopy()
207
33
        : signature.ToByteSource();
208
  }
209
210
44
  return Just(true);
211
}
212
213
44
bool HmacTraits::DeriveBits(
214
    Environment* env,
215
    const HmacConfig& params,
216
    ByteSource* out) {
217
88
  HMACCtxPointer ctx(HMAC_CTX_new());
218
219

88
  if (!ctx ||
220
88
      !HMAC_Init_ex(
221
          ctx.get(),
222
44
          params.key->GetSymmetricKey(),
223
44
          params.key->GetSymmetricKeySize(),
224
44
          params.digest,
225
          nullptr)) {
226
    return false;
227
  }
228
229
44
  if (!HMAC_Update(
230
          ctx.get(),
231
          params.data.data<unsigned char>(),
232
          params.data.size())) {
233
    return false;
234
  }
235
236
44
  char* data = MallocOpenSSL<char>(EVP_MAX_MD_SIZE);
237
88
  ByteSource buf = ByteSource::Allocated(data, EVP_MAX_MD_SIZE);
238
44
  unsigned char* ptr = reinterpret_cast<unsigned char*>(data);
239
  unsigned int len;
240
241
44
  if (!HMAC_Final(ctx.get(), ptr, &len)) {
242
    return false;
243
  }
244
245
44
  buf.Resize(len);
246
44
  *out = std::move(buf);
247
248
44
  return true;
249
}
250
251
44
Maybe<bool> HmacTraits::EncodeOutput(
252
    Environment* env,
253
    const HmacConfig& params,
254
    ByteSource* out,
255
    Local<Value>* result) {
256
44
  switch (params.mode) {
257
    case SignConfiguration::kSign:
258
22
      *result = out->ToArrayBuffer(env);
259
11
      break;
260
    case SignConfiguration::kVerify:
261
33
      *result =
262
66
          out->size() > 0 &&
263
62
          out->size() == params.signature.size() &&
264
29
          memcmp(out->get(), params.signature.get(), out->size()) == 0
265
17
              ? v8::True(env->isolate())
266
83
              : v8::False(env->isolate());
267
33
      break;
268
    default:
269
      UNREACHABLE();
270
  }
271
44
  return Just(!result->IsEmpty());
272
}
273
274
}  // namespace crypto
275

14034
}  // namespace node