Coverage Report

Created: 2025-10-31 09:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/node/src/crypto/crypto_timing.cc
Line
Count
Source
1
#include "crypto/crypto_timing.h"
2
#include "crypto/crypto_util.h"
3
#include "env-inl.h"
4
#include "node.h"
5
#include "node_debug.h"
6
#include "node_errors.h"
7
#include "v8.h"
8
9
#include <openssl/crypto.h>
10
11
namespace node {
12
13
using v8::CFunction;
14
using v8::FastApiCallbackOptions;
15
using v8::FunctionCallbackInfo;
16
using v8::HandleScope;
17
using v8::Local;
18
using v8::Object;
19
using v8::Value;
20
21
namespace crypto {
22
namespace Timing {
23
0
void TimingSafeEqual(const FunctionCallbackInfo<Value>& args) {
24
  // Moving the type checking into JS leads to test failures, most likely due
25
  // to V8 inlining certain parts of the wrapper. Therefore, keep them in C++.
26
  // Refs: https://github.com/nodejs/node/issues/34073.
27
0
  Environment* env = Environment::GetCurrent(args);
28
0
  if (!IsAnyBufferSource(args[0])) {
29
0
    THROW_ERR_INVALID_ARG_TYPE(
30
0
      env, "The \"buf1\" argument must be an instance of "
31
0
      "ArrayBuffer, Buffer, TypedArray, or DataView.");
32
0
    return;
33
0
  }
34
0
  if (!IsAnyBufferSource(args[1])) {
35
0
    THROW_ERR_INVALID_ARG_TYPE(
36
0
      env, "The \"buf2\" argument must be an instance of "
37
0
      "ArrayBuffer, Buffer, TypedArray, or DataView.");
38
0
    return;
39
0
  }
40
41
0
  ArrayBufferOrViewContents<char> buf1(args[0]);
42
0
  ArrayBufferOrViewContents<char> buf2(args[1]);
43
44
0
  if (buf1.size() != buf2.size()) {
45
0
    THROW_ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH(env);
46
0
    return;
47
0
  }
48
49
0
  return args.GetReturnValue().Set(
50
0
      CRYPTO_memcmp(buf1.data(), buf2.data(), buf1.size()) == 0);
51
0
}
52
53
bool FastTimingSafeEqual(Local<Value> receiver,
54
                         Local<Value> a_obj,
55
                         Local<Value> b_obj,
56
                         // NOLINTNEXTLINE(runtime/references)
57
0
                         FastApiCallbackOptions& options) {
58
0
  HandleScope scope(options.isolate);
59
0
  ArrayBufferViewContents<uint8_t> a(a_obj);
60
0
  ArrayBufferViewContents<uint8_t> b(b_obj);
61
0
  if (a.length() != b.length()) {
62
0
    TRACK_V8_FAST_API_CALL("crypto.timingSafeEqual.error");
63
0
    THROW_ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH(options.isolate);
64
0
    return false;
65
0
  }
66
67
0
  TRACK_V8_FAST_API_CALL("crypto.timingSafeEqual.ok");
68
0
  return CRYPTO_memcmp(a.data(), b.data(), a.length()) == 0;
69
0
}
70
71
static CFunction fast_timing_safe_equal(CFunction::Make(FastTimingSafeEqual));
72
73
0
void Initialize(Environment* env, Local<Object> target) {
74
0
  SetFastMethodNoSideEffect(env->context(),
75
0
                            target,
76
0
                            "timingSafeEqual",
77
0
                            TimingSafeEqual,
78
0
                            &fast_timing_safe_equal);
79
0
}
80
0
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
81
0
  registry->Register(TimingSafeEqual);
82
0
  registry->Register(fast_timing_safe_equal);
83
0
}
84
}  // namespace Timing
85
86
}  // namespace crypto
87
}  // namespace node