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: 12 141 8.5 %
Date: 2021-02-19 04:08:54 Branches: 2 83 2.4 %

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
Hmac::Hmac(Environment* env, Local<Object> wrap)
31
    : BaseObject(env, wrap),
32
      ctx_(nullptr) {
33
  MakeWeak();
34
}
35
36
void Hmac::MemoryInfo(MemoryTracker* tracker) const {
37
  tracker->TrackFieldWithSize("context", ctx_ ? kSizeOf_HMAC_CTX : 0);
38
}
39
40
2
void Hmac::Initialize(Environment* env, Local<Object> target) {
41
2
  Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
42
43
6
  t->InstanceTemplate()->SetInternalFieldCount(
44
2
      Hmac::kInternalFieldCount);
45
4
  t->Inherit(BaseObject::GetConstructorTemplate(env));
46
47
2
  env->SetProtoMethod(t, "init", HmacInit);
48
2
  env->SetProtoMethod(t, "update", HmacUpdate);
49
2
  env->SetProtoMethod(t, "digest", HmacDigest);
50
51
2
  env->SetConstructorFunction(target, "Hmac", t);
52
53
2
  HmacJob::Initialize(env, target);
54
2
}
55
56
void Hmac::New(const FunctionCallbackInfo<Value>& args) {
57
  Environment* env = Environment::GetCurrent(args);
58
  new Hmac(env, args.This());
59
}
60
61
void Hmac::HmacInit(const char* hash_type, const char* key, int key_len) {
62
  HandleScope scope(env()->isolate());
63
64
  const EVP_MD* md = EVP_get_digestbyname(hash_type);
65
  if (md == nullptr)
66
    return THROW_ERR_CRYPTO_INVALID_DIGEST(env());
67
  if (key_len == 0) {
68
    key = "";
69
  }
70
  ctx_.reset(HMAC_CTX_new());
71
  if (!ctx_ || !HMAC_Init_ex(ctx_.get(), key, key_len, md, nullptr)) {
72
    ctx_.reset();
73
    return ThrowCryptoError(env(), ERR_get_error());
74
  }
75
}
76
77
void Hmac::HmacInit(const FunctionCallbackInfo<Value>& args) {
78
  Hmac* hmac;
79
  ASSIGN_OR_RETURN_UNWRAP(&hmac, args.Holder());
80
  Environment* env = hmac->env();
81
82
  const node::Utf8Value hash_type(env->isolate(), args[0]);
83
  ByteSource key = ByteSource::FromSecretKeyBytes(env, args[1]);
84
  hmac->HmacInit(*hash_type, key.get(), key.size());
85
}
86
87
bool Hmac::HmacUpdate(const char* data, size_t len) {
88
  return ctx_ && HMAC_Update(ctx_.get(),
89
                             reinterpret_cast<const unsigned char*>(data),
90
                             len) == 1;
91
}
92
93
void Hmac::HmacUpdate(const FunctionCallbackInfo<Value>& args) {
94
  Decode<Hmac>(args, [](Hmac* hmac, const FunctionCallbackInfo<Value>& args,
95
                        const char* data, size_t size) {
96
    Environment* env = Environment::GetCurrent(args);
97
    if (UNLIKELY(size > INT_MAX))
98
      return THROW_ERR_OUT_OF_RANGE(env, "data is too long");
99
    bool r = hmac->HmacUpdate(data, size);
100
    args.GetReturnValue().Set(r);
101
  });
102
}
103
104
void Hmac::HmacDigest(const FunctionCallbackInfo<Value>& args) {
105
  Environment* env = Environment::GetCurrent(args);
106
107
  Hmac* hmac;
108
  ASSIGN_OR_RETURN_UNWRAP(&hmac, args.Holder());
109
110
  enum encoding encoding = BUFFER;
111
  if (args.Length() >= 1) {
112
    encoding = ParseEncoding(env->isolate(), args[0], BUFFER);
113
  }
114
115
  unsigned char md_value[EVP_MAX_MD_SIZE];
116
  unsigned int md_len = 0;
117
118
  if (hmac->ctx_) {
119
    HMAC_Final(hmac->ctx_.get(), md_value, &md_len);
120
    hmac->ctx_.reset();
121
  }
122
123
  Local<Value> error;
124
  MaybeLocal<Value> rc =
125
      StringBytes::Encode(env->isolate(),
126
                          reinterpret_cast<const char*>(md_value),
127
                          md_len,
128
                          encoding,
129
                          &error);
130
  if (rc.IsEmpty()) {
131
    CHECK(!error.IsEmpty());
132
    env->isolate()->ThrowException(error);
133
    return;
134
  }
135
  args.GetReturnValue().Set(rc.FromMaybe(Local<Value>()));
136
}
137
138
HmacConfig::HmacConfig(HmacConfig&& other) noexcept
139
    : job_mode(other.job_mode),
140
      mode(other.mode),
141
      key(std::move(other.key)),
142
      data(std::move(other.data)),
143
      signature(std::move(other.signature)),
144
      digest(other.digest) {}
145
146
HmacConfig& HmacConfig::operator=(HmacConfig&& other) noexcept {
147
  if (&other == this) return *this;
148
  this->~HmacConfig();
149
  return *new (this) HmacConfig(std::move(other));
150
}
151
152
void HmacConfig::MemoryInfo(MemoryTracker* tracker) const {
153
  tracker->TrackField("key", key.get());
154
  // If the job is sync, then the HmacConfig does not own the data
155
  if (job_mode == kCryptoJobAsync) {
156
    tracker->TrackFieldWithSize("data", data.size());
157
    tracker->TrackFieldWithSize("signature", signature.size());
158
  }
159
}
160
161
Maybe<bool> HmacTraits::AdditionalConfig(
162
    CryptoJobMode mode,
163
    const FunctionCallbackInfo<Value>& args,
164
    unsigned int offset,
165
    HmacConfig* params) {
166
  Environment* env = Environment::GetCurrent(args);
167
168
  params->job_mode = mode;
169
170
  CHECK(args[offset]->IsUint32());  // SignConfiguration::Mode
171
  params->mode =
172
    static_cast<SignConfiguration::Mode>(args[offset].As<Uint32>()->Value());
173
174
  CHECK(args[offset + 1]->IsString());  // Hash
175
  CHECK(args[offset + 2]->IsObject());  // Key
176
177
  Utf8Value digest(env->isolate(), args[offset + 1]);
178
  params->digest = EVP_get_digestbyname(*digest);
179
  if (params->digest == nullptr) {
180
    THROW_ERR_CRYPTO_INVALID_DIGEST(env);
181
    return Nothing<bool>();
182
  }
183
184
  KeyObjectHandle* key;
185
  ASSIGN_OR_RETURN_UNWRAP(&key, args[offset + 2], Nothing<bool>());
186
  params->key = key->Data();
187
188
  ArrayBufferOrViewContents<char> data(args[offset + 3]);
189
  if (UNLIKELY(!data.CheckSizeInt32())) {
190
    THROW_ERR_OUT_OF_RANGE(env, "data is too big");
191
    return Nothing<bool>();
192
  }
193
  params->data = mode == kCryptoJobAsync
194
      ? data.ToCopy()
195
      : data.ToByteSource();
196
197
  if (!args[offset + 4]->IsUndefined()) {
198
    ArrayBufferOrViewContents<char> signature(args[offset + 4]);
199
    if (UNLIKELY(!signature.CheckSizeInt32())) {
200
      THROW_ERR_OUT_OF_RANGE(env, "signature is too big");
201
      return Nothing<bool>();
202
    }
203
    params->signature = mode == kCryptoJobAsync
204
        ? signature.ToCopy()
205
        : signature.ToByteSource();
206
  }
207
208
  return Just(true);
209
}
210
211
bool HmacTraits::DeriveBits(
212
    Environment* env,
213
    const HmacConfig& params,
214
    ByteSource* out) {
215
  HMACCtxPointer ctx(HMAC_CTX_new());
216
217
  if (!ctx ||
218
      !HMAC_Init_ex(
219
          ctx.get(),
220
          params.key->GetSymmetricKey(),
221
          params.key->GetSymmetricKeySize(),
222
          params.digest,
223
          nullptr)) {
224
    return false;
225
  }
226
227
  if (!HMAC_Update(
228
          ctx.get(),
229
          params.data.data<unsigned char>(),
230
          params.data.size())) {
231
    return false;
232
  }
233
234
  char* data = MallocOpenSSL<char>(EVP_MAX_MD_SIZE);
235
  ByteSource buf = ByteSource::Allocated(data, EVP_MAX_MD_SIZE);
236
  unsigned char* ptr = reinterpret_cast<unsigned char*>(data);
237
  unsigned int len;
238
239
  if (!HMAC_Final(ctx.get(), ptr, &len)) {
240
    return false;
241
  }
242
243
  buf.Resize(len);
244
  *out = std::move(buf);
245
246
  return true;
247
}
248
249
Maybe<bool> HmacTraits::EncodeOutput(
250
    Environment* env,
251
    const HmacConfig& params,
252
    ByteSource* out,
253
    Local<Value>* result) {
254
  switch (params.mode) {
255
    case SignConfiguration::kSign:
256
      *result = out->ToArrayBuffer(env);
257
      break;
258
    case SignConfiguration::kVerify:
259
      *result =
260
          out->size() > 0 &&
261
          out->size() == params.signature.size() &&
262
          memcmp(out->get(), params.signature.get(), out->size()) == 0
263
              ? v8::True(env->isolate())
264
              : v8::False(env->isolate());
265
      break;
266
    default:
267
      UNREACHABLE();
268
  }
269
  return Just(!result->IsEmpty());
270
}
271
272
}  // namespace crypto
273

366
}  // namespace node