Coverage Report

Created: 2025-07-04 09:33

/src/node/src/crypto/crypto_cipher.cc
Line
Count
Source (jump to first uncovered line)
1
#include "crypto/crypto_cipher.h"
2
#include "base_object-inl.h"
3
#include "crypto/crypto_util.h"
4
#include "env-inl.h"
5
#include "memory_tracker-inl.h"
6
#include "node_buffer.h"
7
#include "node_internals.h"
8
#include "node_process-inl.h"
9
#include "v8.h"
10
11
namespace node {
12
13
using v8::Array;
14
using v8::ArrayBuffer;
15
using v8::BackingStore;
16
using v8::Context;
17
using v8::FunctionCallbackInfo;
18
using v8::FunctionTemplate;
19
using v8::HandleScope;
20
using v8::Int32;
21
using v8::Isolate;
22
using v8::Local;
23
using v8::Object;
24
using v8::Uint32;
25
using v8::Value;
26
27
namespace crypto {
28
namespace {
29
49
bool IsSupportedAuthenticatedMode(const EVP_CIPHER* cipher) {
30
49
  switch (EVP_CIPHER_mode(cipher)) {
31
30
  case EVP_CIPH_CCM_MODE:
32
30
  case EVP_CIPH_GCM_MODE:
33
30
#ifndef OPENSSL_NO_OCB
34
30
  case EVP_CIPH_OCB_MODE:
35
30
#endif
36
30
    return true;
37
0
  case EVP_CIPH_STREAM_CIPHER:
38
0
    return EVP_CIPHER_nid(cipher) == NID_chacha20_poly1305;
39
19
  default:
40
19
    return false;
41
49
  }
42
49
}
43
44
31
bool IsSupportedAuthenticatedMode(const EVP_CIPHER_CTX* ctx) {
45
31
  const EVP_CIPHER* cipher = EVP_CIPHER_CTX_cipher(ctx);
46
31
  return IsSupportedAuthenticatedMode(cipher);
47
31
}
48
49
0
bool IsValidGCMTagLength(unsigned int tag_len) {
50
0
  return tag_len == 4 || tag_len == 8 || (tag_len >= 12 && tag_len <= 16);
51
0
}
52
53
// Collects and returns information on the given cipher
54
0
void GetCipherInfo(const FunctionCallbackInfo<Value>& args) {
55
0
  Environment* env = Environment::GetCurrent(args);
56
0
  CHECK(args[0]->IsObject());
57
0
  Local<Object> info = args[0].As<Object>();
58
59
0
  CHECK(args[1]->IsString() || args[1]->IsInt32());
60
61
0
  const EVP_CIPHER* cipher;
62
0
  if (args[1]->IsString()) {
63
0
    Utf8Value name(env->isolate(), args[1]);
64
0
    cipher = EVP_get_cipherbyname(*name);
65
0
  } else {
66
0
    int nid = args[1].As<Int32>()->Value();
67
0
    cipher = EVP_get_cipherbynid(nid);
68
0
  }
69
70
0
  if (cipher == nullptr)
71
0
    return;
72
73
0
  int mode = EVP_CIPHER_mode(cipher);
74
0
  int iv_length = EVP_CIPHER_iv_length(cipher);
75
0
  int key_length = EVP_CIPHER_key_length(cipher);
76
0
  int block_length = EVP_CIPHER_block_size(cipher);
77
0
  const char* mode_label = nullptr;
78
0
  switch (mode) {
79
0
    case EVP_CIPH_CBC_MODE: mode_label = "cbc"; break;
80
0
    case EVP_CIPH_CCM_MODE: mode_label = "ccm"; break;
81
0
    case EVP_CIPH_CFB_MODE: mode_label = "cfb"; break;
82
0
    case EVP_CIPH_CTR_MODE: mode_label = "ctr"; break;
83
0
    case EVP_CIPH_ECB_MODE: mode_label = "ecb"; break;
84
0
    case EVP_CIPH_GCM_MODE: mode_label = "gcm"; break;
85
0
    case EVP_CIPH_OCB_MODE: mode_label = "ocb"; break;
86
0
    case EVP_CIPH_OFB_MODE: mode_label = "ofb"; break;
87
0
    case EVP_CIPH_WRAP_MODE: mode_label = "wrap"; break;
88
0
    case EVP_CIPH_XTS_MODE: mode_label = "xts"; break;
89
0
    case EVP_CIPH_STREAM_CIPHER: mode_label = "stream"; break;
90
0
  }
91
92
  // If the testKeyLen and testIvLen arguments are specified,
93
  // then we will make an attempt to see if they are usable for
94
  // the cipher in question, returning undefined if they are not.
95
  // If they are, the info object will be returned with the values
96
  // given.
97
0
  if (args[2]->IsInt32() || args[3]->IsInt32()) {
98
    // Test and input IV or key length to determine if it's acceptable.
99
    // If it is, then the getCipherInfo will succeed with the given
100
    // values.
101
0
    CipherCtxPointer ctx(EVP_CIPHER_CTX_new());
102
0
    if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr, nullptr, nullptr, 1))
103
0
      return;
104
105
0
    if (args[2]->IsInt32()) {
106
0
      int check_len = args[2].As<Int32>()->Value();
107
0
      if (!EVP_CIPHER_CTX_set_key_length(ctx.get(), check_len))
108
0
        return;
109
0
      key_length = check_len;
110
0
    }
111
112
0
    if (args[3]->IsInt32()) {
113
0
      int check_len = args[3].As<Int32>()->Value();
114
      // For CCM modes, the IV may be between 7 and 13 bytes.
115
      // For GCM and OCB modes, we'll check by attempting to
116
      // set the value. For everything else, just check that
117
      // check_len == iv_length.
118
0
      switch (mode) {
119
0
        case EVP_CIPH_CCM_MODE:
120
0
          if (check_len < 7 || check_len > 13)
121
0
            return;
122
0
          break;
123
0
        case EVP_CIPH_GCM_MODE:
124
          // Fall through
125
0
        case EVP_CIPH_OCB_MODE:
126
0
          if (!EVP_CIPHER_CTX_ctrl(
127
0
                  ctx.get(),
128
0
                  EVP_CTRL_AEAD_SET_IVLEN,
129
0
                  check_len,
130
0
                  nullptr)) {
131
0
            return;
132
0
          }
133
0
          break;
134
0
        default:
135
0
          if (check_len != iv_length)
136
0
            return;
137
0
      }
138
0
      iv_length = check_len;
139
0
    }
140
0
  }
141
142
0
  if (mode_label != nullptr &&
143
0
      info->Set(
144
0
          env->context(),
145
0
          FIXED_ONE_BYTE_STRING(env->isolate(), "mode"),
146
0
          OneByteString(env->isolate(), mode_label)).IsNothing()) {
147
0
    return;
148
0
  }
149
150
  // OBJ_nid2sn(EVP_CIPHER_nid(cipher)) is used here instead of
151
  // EVP_CIPHER_name(cipher) for compatibility with BoringSSL.
152
0
  if (info->Set(
153
0
          env->context(),
154
0
          env->name_string(),
155
0
          OneByteString(
156
0
            env->isolate(),
157
0
            OBJ_nid2sn(EVP_CIPHER_nid(cipher)))).IsNothing()) {
158
0
    return;
159
0
  }
160
161
0
  if (info->Set(
162
0
          env->context(),
163
0
          FIXED_ONE_BYTE_STRING(env->isolate(), "nid"),
164
0
          Int32::New(env->isolate(), EVP_CIPHER_nid(cipher))).IsNothing()) {
165
0
    return;
166
0
  }
167
168
  // Stream ciphers do not have a meaningful block size
169
0
  if (mode != EVP_CIPH_STREAM_CIPHER &&
170
0
      info->Set(
171
0
          env->context(),
172
0
          FIXED_ONE_BYTE_STRING(env->isolate(), "blockSize"),
173
0
          Int32::New(env->isolate(), block_length)).IsNothing()) {
174
0
    return;
175
0
  }
176
177
  // Ciphers that do not use an IV shouldn't report a length
178
0
  if (iv_length != 0 &&
179
0
      info->Set(
180
0
          env->context(),
181
0
          FIXED_ONE_BYTE_STRING(env->isolate(), "ivLength"),
182
0
          Int32::New(env->isolate(), iv_length)).IsNothing()) {
183
0
    return;
184
0
  }
185
186
0
  if (info->Set(
187
0
          env->context(),
188
0
          FIXED_ONE_BYTE_STRING(env->isolate(), "keyLength"),
189
0
          Int32::New(env->isolate(), key_length)).IsNothing()) {
190
0
    return;
191
0
  }
192
193
0
  args.GetReturnValue().Set(info);
194
0
}
195
}  // namespace
196
197
0
void CipherBase::GetSSLCiphers(const FunctionCallbackInfo<Value>& args) {
198
0
  Environment* env = Environment::GetCurrent(args);
199
200
0
  SSLCtxPointer ctx(SSL_CTX_new(TLS_method()));
201
0
  if (!ctx) {
202
0
    return ThrowCryptoError(env, ERR_get_error(), "SSL_CTX_new");
203
0
  }
204
205
0
  SSLPointer ssl(SSL_new(ctx.get()));
206
0
  if (!ssl) {
207
0
    return ThrowCryptoError(env, ERR_get_error(), "SSL_new");
208
0
  }
209
210
0
  STACK_OF(SSL_CIPHER)* ciphers = SSL_get_ciphers(ssl.get());
211
212
  // TLSv1.3 ciphers aren't listed by EVP. There are only 5, we could just
213
  // document them, but since there are only 5, easier to just add them manually
214
  // and not have to explain their absence in the API docs. They are lower-cased
215
  // because the docs say they will be.
216
0
  static const char* TLS13_CIPHERS[] = {
217
0
    "tls_aes_256_gcm_sha384",
218
0
    "tls_chacha20_poly1305_sha256",
219
0
    "tls_aes_128_gcm_sha256",
220
0
    "tls_aes_128_ccm_8_sha256",
221
0
    "tls_aes_128_ccm_sha256"
222
0
  };
223
224
0
  const int n = sk_SSL_CIPHER_num(ciphers);
225
0
  std::vector<Local<Value>> arr(n + arraysize(TLS13_CIPHERS));
226
227
0
  for (int i = 0; i < n; ++i) {
228
0
    const SSL_CIPHER* cipher = sk_SSL_CIPHER_value(ciphers, i);
229
0
    arr[i] = OneByteString(env->isolate(), SSL_CIPHER_get_name(cipher));
230
0
  }
231
232
0
  for (unsigned i = 0; i < arraysize(TLS13_CIPHERS); ++i) {
233
0
    const char* name = TLS13_CIPHERS[i];
234
0
    arr[n + i] = OneByteString(env->isolate(), name);
235
0
  }
236
237
0
  args.GetReturnValue().Set(Array::New(env->isolate(), arr.data(), arr.size()));
238
0
}
239
240
1
void CipherBase::GetCiphers(const FunctionCallbackInfo<Value>& args) {
241
1
  Environment* env = Environment::GetCurrent(args);
242
1
  MarkPopErrorOnReturn mark_pop_error_on_return;
243
1
  CipherPushContext ctx(env);
244
1
  EVP_CIPHER_do_all_sorted(
245
1
#if OPENSSL_VERSION_MAJOR >= 3
246
1
    array_push_back<EVP_CIPHER,
247
1
                    EVP_CIPHER_fetch,
248
1
                    EVP_CIPHER_free,
249
1
                    EVP_get_cipherbyname,
250
1
                    EVP_CIPHER_get0_name>,
251
#else
252
    array_push_back<EVP_CIPHER>,
253
#endif
254
1
    &ctx);
255
1
  args.GetReturnValue().Set(ctx.ToJSArray());
256
1
}
257
258
CipherBase::CipherBase(Environment* env,
259
                       Local<Object> wrap,
260
                       CipherKind kind)
261
9
    : BaseObject(env, wrap),
262
9
      ctx_(nullptr),
263
9
      kind_(kind),
264
9
      auth_tag_state_(kAuthTagUnknown),
265
9
      auth_tag_len_(kNoAuthTagLength),
266
9
      pending_auth_failed_(false) {
267
9
  MakeWeak();
268
9
}
269
270
0
void CipherBase::MemoryInfo(MemoryTracker* tracker) const {
271
0
  tracker->TrackFieldWithSize("context", ctx_ ? kSizeOf_EVP_CIPHER_CTX : 0);
272
0
}
273
274
9.32k
void CipherBase::Initialize(Environment* env, Local<Object> target) {
275
9.32k
  Isolate* isolate = env->isolate();
276
9.32k
  Local<Context> context = env->context();
277
278
9.32k
  Local<FunctionTemplate> t = NewFunctionTemplate(isolate, New);
279
280
9.32k
  t->InstanceTemplate()->SetInternalFieldCount(CipherBase::kInternalFieldCount);
281
282
9.32k
  SetProtoMethod(isolate, t, "init", Init);
283
9.32k
  SetProtoMethod(isolate, t, "initiv", InitIv);
284
9.32k
  SetProtoMethod(isolate, t, "update", Update);
285
9.32k
  SetProtoMethod(isolate, t, "final", Final);
286
9.32k
  SetProtoMethod(isolate, t, "setAutoPadding", SetAutoPadding);
287
9.32k
  SetProtoMethodNoSideEffect(isolate, t, "getAuthTag", GetAuthTag);
288
9.32k
  SetProtoMethod(isolate, t, "setAuthTag", SetAuthTag);
289
9.32k
  SetProtoMethod(isolate, t, "setAAD", SetAAD);
290
9.32k
  SetConstructorFunction(context, target, "CipherBase", t);
291
292
9.32k
  SetMethodNoSideEffect(context, target, "getSSLCiphers", GetSSLCiphers);
293
9.32k
  SetMethodNoSideEffect(context, target, "getCiphers", GetCiphers);
294
295
9.32k
  SetMethod(context,
296
9.32k
            target,
297
9.32k
            "publicEncrypt",
298
9.32k
            PublicKeyCipher::Cipher<PublicKeyCipher::kPublic,
299
9.32k
                                    EVP_PKEY_encrypt_init,
300
9.32k
                                    EVP_PKEY_encrypt>);
301
9.32k
  SetMethod(context,
302
9.32k
            target,
303
9.32k
            "privateDecrypt",
304
9.32k
            PublicKeyCipher::Cipher<PublicKeyCipher::kPrivate,
305
9.32k
                                    EVP_PKEY_decrypt_init,
306
9.32k
                                    EVP_PKEY_decrypt>);
307
9.32k
  SetMethod(context,
308
9.32k
            target,
309
9.32k
            "privateEncrypt",
310
9.32k
            PublicKeyCipher::Cipher<PublicKeyCipher::kPrivate,
311
9.32k
                                    EVP_PKEY_sign_init,
312
9.32k
                                    EVP_PKEY_sign>);
313
9.32k
  SetMethod(context,
314
9.32k
            target,
315
9.32k
            "publicDecrypt",
316
9.32k
            PublicKeyCipher::Cipher<PublicKeyCipher::kPublic,
317
9.32k
                                    EVP_PKEY_verify_recover_init,
318
9.32k
                                    EVP_PKEY_verify_recover>);
319
320
9.32k
  SetMethodNoSideEffect(context, target, "getCipherInfo", GetCipherInfo);
321
322
9.32k
  NODE_DEFINE_CONSTANT(target, kWebCryptoCipherEncrypt);
323
9.32k
  NODE_DEFINE_CONSTANT(target, kWebCryptoCipherDecrypt);
324
9.32k
}
325
326
void CipherBase::RegisterExternalReferences(
327
0
    ExternalReferenceRegistry* registry) {
328
0
  registry->Register(New);
329
330
0
  registry->Register(Init);
331
0
  registry->Register(InitIv);
332
0
  registry->Register(Update);
333
0
  registry->Register(Final);
334
0
  registry->Register(SetAutoPadding);
335
0
  registry->Register(GetAuthTag);
336
0
  registry->Register(SetAuthTag);
337
0
  registry->Register(SetAAD);
338
339
0
  registry->Register(GetSSLCiphers);
340
0
  registry->Register(GetCiphers);
341
342
0
  registry->Register(PublicKeyCipher::Cipher<PublicKeyCipher::kPublic,
343
0
                                             EVP_PKEY_encrypt_init,
344
0
                                             EVP_PKEY_encrypt>);
345
0
  registry->Register(PublicKeyCipher::Cipher<PublicKeyCipher::kPrivate,
346
0
                                             EVP_PKEY_decrypt_init,
347
0
                                             EVP_PKEY_decrypt>);
348
0
  registry->Register(PublicKeyCipher::Cipher<PublicKeyCipher::kPrivate,
349
0
                                             EVP_PKEY_sign_init,
350
0
                                             EVP_PKEY_sign>);
351
0
  registry->Register(PublicKeyCipher::Cipher<PublicKeyCipher::kPublic,
352
0
                                             EVP_PKEY_verify_recover_init,
353
0
                                             EVP_PKEY_verify_recover>);
354
355
0
  registry->Register(GetCipherInfo);
356
0
}
357
358
9
void CipherBase::New(const FunctionCallbackInfo<Value>& args) {
359
9
  CHECK(args.IsConstructCall());
360
9
  Environment* env = Environment::GetCurrent(args);
361
9
  new CipherBase(env, args.This(), args[0]->IsTrue() ? kCipher : kDecipher);
362
9
}
363
364
void CipherBase::CommonInit(const char* cipher_type,
365
                            const EVP_CIPHER* cipher,
366
                            const unsigned char* key,
367
                            int key_len,
368
                            const unsigned char* iv,
369
                            int iv_len,
370
9
                            unsigned int auth_tag_len) {
371
9
  CHECK(!ctx_);
372
9
  ctx_.reset(EVP_CIPHER_CTX_new());
373
374
9
  const int mode = EVP_CIPHER_mode(cipher);
375
9
  if (mode == EVP_CIPH_WRAP_MODE)
376
0
    EVP_CIPHER_CTX_set_flags(ctx_.get(), EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
377
378
9
  const bool encrypt = (kind_ == kCipher);
379
9
  if (1 != EVP_CipherInit_ex(ctx_.get(), cipher, nullptr,
380
9
                             nullptr, nullptr, encrypt)) {
381
0
    return ThrowCryptoError(env(), ERR_get_error(),
382
0
                            "Failed to initialize cipher");
383
0
  }
384
385
9
  if (IsSupportedAuthenticatedMode(cipher)) {
386
4
    CHECK_GE(iv_len, 0);
387
4
    if (!InitAuthenticated(cipher_type, iv_len, auth_tag_len))
388
0
      return;
389
4
  }
390
391
9
  if (!EVP_CIPHER_CTX_set_key_length(ctx_.get(), key_len)) {
392
0
    ctx_.reset();
393
0
    return THROW_ERR_CRYPTO_INVALID_KEYLEN(env());
394
0
  }
395
396
9
  if (1 != EVP_CipherInit_ex(ctx_.get(), nullptr, nullptr, key, iv, encrypt)) {
397
0
    return ThrowCryptoError(env(), ERR_get_error(),
398
0
                            "Failed to initialize cipher");
399
0
  }
400
9
}
401
402
void CipherBase::Init(const char* cipher_type,
403
                      const ArrayBufferOrViewContents<unsigned char>& key_buf,
404
0
                      unsigned int auth_tag_len) {
405
0
  HandleScope scope(env()->isolate());
406
0
  MarkPopErrorOnReturn mark_pop_error_on_return;
407
0
  const EVP_CIPHER* const cipher = EVP_get_cipherbyname(cipher_type);
408
0
  if (cipher == nullptr)
409
0
    return THROW_ERR_CRYPTO_UNKNOWN_CIPHER(env());
410
411
0
  unsigned char key[EVP_MAX_KEY_LENGTH];
412
0
  unsigned char iv[EVP_MAX_IV_LENGTH];
413
414
0
  int key_len = EVP_BytesToKey(cipher,
415
0
                               EVP_md5(),
416
0
                               nullptr,
417
0
                               key_buf.data(),
418
0
                               key_buf.size(),
419
0
                               1,
420
0
                               key,
421
0
                               iv);
422
0
  CHECK_NE(key_len, 0);
423
424
0
  const int mode = EVP_CIPHER_mode(cipher);
425
0
  if (kind_ == kCipher && (mode == EVP_CIPH_CTR_MODE ||
426
0
                           mode == EVP_CIPH_GCM_MODE ||
427
0
                           mode == EVP_CIPH_CCM_MODE)) {
428
    // Ignore the return value (i.e. possible exception) because we are
429
    // not calling back into JS anyway.
430
0
    ProcessEmitWarning(env(),
431
0
                       "Use Cipheriv for counter mode of %s",
432
0
                       cipher_type);
433
0
  }
434
435
0
  CommonInit(cipher_type, cipher, key, key_len, iv,
436
0
             EVP_CIPHER_iv_length(cipher), auth_tag_len);
437
0
}
438
439
0
void CipherBase::Init(const FunctionCallbackInfo<Value>& args) {
440
0
  CipherBase* cipher;
441
0
  ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder());
442
0
  Environment* env = Environment::GetCurrent(args);
443
444
0
  CHECK_GE(args.Length(), 3);
445
446
0
  const Utf8Value cipher_type(args.GetIsolate(), args[0]);
447
0
  ArrayBufferOrViewContents<unsigned char> key_buf(args[1]);
448
0
  if (!key_buf.CheckSizeInt32())
449
0
    return THROW_ERR_OUT_OF_RANGE(env, "password is too large");
450
451
  // Don't assign to cipher->auth_tag_len_ directly; the value might not
452
  // represent a valid length at this point.
453
0
  unsigned int auth_tag_len;
454
0
  if (args[2]->IsUint32()) {
455
0
    auth_tag_len = args[2].As<Uint32>()->Value();
456
0
  } else {
457
0
    CHECK(args[2]->IsInt32() && args[2].As<Int32>()->Value() == -1);
458
0
    auth_tag_len = kNoAuthTagLength;
459
0
  }
460
461
0
  cipher->Init(*cipher_type, key_buf, auth_tag_len);
462
0
}
463
464
void CipherBase::InitIv(const char* cipher_type,
465
                        const ByteSource& key_buf,
466
                        const ArrayBufferOrViewContents<unsigned char>& iv_buf,
467
9
                        unsigned int auth_tag_len) {
468
9
  HandleScope scope(env()->isolate());
469
9
  MarkPopErrorOnReturn mark_pop_error_on_return;
470
471
9
  const EVP_CIPHER* const cipher = EVP_get_cipherbyname(cipher_type);
472
9
  if (cipher == nullptr)
473
0
    return THROW_ERR_CRYPTO_UNKNOWN_CIPHER(env());
474
475
9
  const int expected_iv_len = EVP_CIPHER_iv_length(cipher);
476
9
  const bool is_authenticated_mode = IsSupportedAuthenticatedMode(cipher);
477
9
  const bool has_iv = iv_buf.size() > 0;
478
479
  // Throw if no IV was passed and the cipher requires an IV
480
9
  if (!has_iv && expected_iv_len != 0)
481
0
    return THROW_ERR_CRYPTO_INVALID_IV(env());
482
483
  // Throw if an IV was passed which does not match the cipher's fixed IV length
484
  // static_cast<int> for the iv_buf.size() is safe because we've verified
485
  // prior that the value is not larger than INT_MAX.
486
9
  if (!is_authenticated_mode &&
487
9
      has_iv &&
488
9
      static_cast<int>(iv_buf.size()) != expected_iv_len) {
489
0
    return THROW_ERR_CRYPTO_INVALID_IV(env());
490
0
  }
491
492
9
  if (EVP_CIPHER_nid(cipher) == NID_chacha20_poly1305) {
493
0
    CHECK(has_iv);
494
    // Check for invalid IV lengths, since OpenSSL does not under some
495
    // conditions:
496
    //   https://www.openssl.org/news/secadv/20190306.txt.
497
0
    if (iv_buf.size() > 12)
498
0
      return THROW_ERR_CRYPTO_INVALID_IV(env());
499
0
  }
500
501
9
  CommonInit(
502
9
      cipher_type,
503
9
      cipher,
504
9
      key_buf.data<unsigned char>(),
505
9
      key_buf.size(),
506
9
      iv_buf.data(),
507
9
      iv_buf.size(),
508
9
      auth_tag_len);
509
9
}
510
511
9
void CipherBase::InitIv(const FunctionCallbackInfo<Value>& args) {
512
9
  CipherBase* cipher;
513
9
  ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder());
514
9
  Environment* env = cipher->env();
515
516
9
  CHECK_GE(args.Length(), 4);
517
518
9
  const Utf8Value cipher_type(env->isolate(), args[0]);
519
520
  // The argument can either be a KeyObjectHandle or a byte source
521
  // (e.g. ArrayBuffer, TypedArray, etc). Whichever it is, grab the
522
  // raw bytes and proceed...
523
9
  const ByteSource key_buf = ByteSource::FromSecretKeyBytes(env, args[1]);
524
525
9
  if (UNLIKELY(key_buf.size() > INT_MAX))
526
0
    return THROW_ERR_OUT_OF_RANGE(env, "key is too big");
527
528
9
  ArrayBufferOrViewContents<unsigned char> iv_buf(
529
9
      !args[2]->IsNull() ? args[2] : Local<Value>());
530
531
9
  if (UNLIKELY(!iv_buf.CheckSizeInt32()))
532
0
    return THROW_ERR_OUT_OF_RANGE(env, "iv is too big");
533
534
  // Don't assign to cipher->auth_tag_len_ directly; the value might not
535
  // represent a valid length at this point.
536
9
  unsigned int auth_tag_len;
537
9
  if (args[3]->IsUint32()) {
538
4
    auth_tag_len = args[3].As<Uint32>()->Value();
539
5
  } else {
540
5
    CHECK(args[3]->IsInt32() && args[3].As<Int32>()->Value() == -1);
541
5
    auth_tag_len = kNoAuthTagLength;
542
5
  }
543
544
9
  cipher->InitIv(*cipher_type, key_buf, iv_buf, auth_tag_len);
545
9
}
546
547
bool CipherBase::InitAuthenticated(
548
    const char* cipher_type,
549
    int iv_len,
550
4
    unsigned int auth_tag_len) {
551
4
  CHECK(IsAuthenticatedMode());
552
4
  MarkPopErrorOnReturn mark_pop_error_on_return;
553
554
4
  if (!EVP_CIPHER_CTX_ctrl(ctx_.get(),
555
4
                           EVP_CTRL_AEAD_SET_IVLEN,
556
4
                           iv_len,
557
4
                           nullptr)) {
558
0
    THROW_ERR_CRYPTO_INVALID_IV(env());
559
0
    return false;
560
0
  }
561
562
4
  const int mode = EVP_CIPHER_CTX_mode(ctx_.get());
563
4
  if (mode == EVP_CIPH_GCM_MODE) {
564
0
    if (auth_tag_len != kNoAuthTagLength) {
565
0
      if (!IsValidGCMTagLength(auth_tag_len)) {
566
0
        THROW_ERR_CRYPTO_INVALID_AUTH_TAG(
567
0
          env(),
568
0
          "Invalid authentication tag length: %u",
569
0
          auth_tag_len);
570
0
        return false;
571
0
      }
572
573
      // Remember the given authentication tag length for later.
574
0
      auth_tag_len_ = auth_tag_len;
575
0
    }
576
4
  } else {
577
4
    if (auth_tag_len == kNoAuthTagLength) {
578
      // We treat ChaCha20-Poly1305 specially. Like GCM, the authentication tag
579
      // length defaults to 16 bytes when encrypting. Unlike GCM, the
580
      // authentication tag length also defaults to 16 bytes when decrypting,
581
      // whereas GCM would accept any valid authentication tag length.
582
0
      if (EVP_CIPHER_CTX_nid(ctx_.get()) == NID_chacha20_poly1305) {
583
0
        auth_tag_len = 16;
584
0
      } else {
585
0
        THROW_ERR_CRYPTO_INVALID_AUTH_TAG(
586
0
          env(), "authTagLength required for %s", cipher_type);
587
0
        return false;
588
0
      }
589
0
    }
590
591
    // TODO(tniessen) Support CCM decryption in FIPS mode
592
593
4
#if OPENSSL_VERSION_MAJOR >= 3
594
4
    if (mode == EVP_CIPH_CCM_MODE && kind_ == kDecipher &&
595
4
        EVP_default_properties_is_fips_enabled(nullptr)) {
596
#else
597
    if (mode == EVP_CIPH_CCM_MODE && kind_ == kDecipher && FIPS_mode()) {
598
#endif
599
0
      THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env(),
600
0
          "CCM encryption not supported in FIPS mode");
601
0
      return false;
602
0
    }
603
604
    // Tell OpenSSL about the desired length.
605
4
    if (!EVP_CIPHER_CTX_ctrl(ctx_.get(), EVP_CTRL_AEAD_SET_TAG, auth_tag_len,
606
4
                             nullptr)) {
607
0
      THROW_ERR_CRYPTO_INVALID_AUTH_TAG(
608
0
          env(), "Invalid authentication tag length: %u", auth_tag_len);
609
0
      return false;
610
0
    }
611
612
    // Remember the given authentication tag length for later.
613
4
    auth_tag_len_ = auth_tag_len;
614
615
4
    if (mode == EVP_CIPH_CCM_MODE) {
616
      // Restrict the message length to min(INT_MAX, 2^(8*(15-iv_len))-1) bytes.
617
4
      CHECK(iv_len >= 7 && iv_len <= 13);
618
4
      max_message_size_ = INT_MAX;
619
4
      if (iv_len == 12) max_message_size_ = 16777215;
620
4
      if (iv_len == 13) max_message_size_ = 65535;
621
4
    }
622
4
  }
623
624
4
  return true;
625
4
}
626
627
8
bool CipherBase::CheckCCMMessageLength(int message_len) {
628
8
  CHECK(ctx_);
629
8
  CHECK(EVP_CIPHER_CTX_mode(ctx_.get()) == EVP_CIPH_CCM_MODE);
630
631
8
  if (message_len > max_message_size_) {
632
0
    THROW_ERR_CRYPTO_INVALID_MESSAGELEN(env());
633
0
    return false;
634
0
  }
635
636
8
  return true;
637
8
}
638
639
24
bool CipherBase::IsAuthenticatedMode() const {
640
  // Check if this cipher operates in an AEAD mode that we support.
641
24
  CHECK(ctx_);
642
24
  return IsSupportedAuthenticatedMode(ctx_.get());
643
24
}
644
645
2
void CipherBase::GetAuthTag(const FunctionCallbackInfo<Value>& args) {
646
2
  Environment* env = Environment::GetCurrent(args);
647
2
  CipherBase* cipher;
648
2
  ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder());
649
650
  // Only callable after Final and if encrypting.
651
2
  if (cipher->ctx_ ||
652
2
      cipher->kind_ != kCipher ||
653
2
      cipher->auth_tag_len_ == kNoAuthTagLength) {
654
0
    return;
655
0
  }
656
657
2
  args.GetReturnValue().Set(
658
2
      Buffer::Copy(env, cipher->auth_tag_, cipher->auth_tag_len_)
659
2
          .FromMaybe(Local<Value>()));
660
2
}
661
662
2
void CipherBase::SetAuthTag(const FunctionCallbackInfo<Value>& args) {
663
2
  CipherBase* cipher;
664
2
  ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder());
665
2
  Environment* env = Environment::GetCurrent(args);
666
667
2
  if (!cipher->ctx_ ||
668
2
      !cipher->IsAuthenticatedMode() ||
669
2
      cipher->kind_ != kDecipher ||
670
2
      cipher->auth_tag_state_ != kAuthTagUnknown) {
671
0
    return args.GetReturnValue().Set(false);
672
0
  }
673
674
2
  ArrayBufferOrViewContents<char> auth_tag(args[0]);
675
2
  if (UNLIKELY(!auth_tag.CheckSizeInt32()))
676
0
    return THROW_ERR_OUT_OF_RANGE(env, "buffer is too big");
677
678
2
  unsigned int tag_len = auth_tag.size();
679
680
2
  const int mode = EVP_CIPHER_CTX_mode(cipher->ctx_.get());
681
2
  bool is_valid;
682
2
  if (mode == EVP_CIPH_GCM_MODE) {
683
    // Restrict GCM tag lengths according to NIST 800-38d, page 9.
684
0
    is_valid = (cipher->auth_tag_len_ == kNoAuthTagLength ||
685
0
                cipher->auth_tag_len_ == tag_len) &&
686
0
               IsValidGCMTagLength(tag_len);
687
2
  } else {
688
    // At this point, the tag length is already known and must match the
689
    // length of the given authentication tag.
690
2
    CHECK(IsSupportedAuthenticatedMode(cipher->ctx_.get()));
691
2
    CHECK_NE(cipher->auth_tag_len_, kNoAuthTagLength);
692
2
    is_valid = cipher->auth_tag_len_ == tag_len;
693
2
  }
694
695
2
  if (!is_valid) {
696
0
    return THROW_ERR_CRYPTO_INVALID_AUTH_TAG(
697
0
      env, "Invalid authentication tag length: %u", tag_len);
698
0
  }
699
700
2
  cipher->auth_tag_len_ = tag_len;
701
2
  cipher->auth_tag_state_ = kAuthTagKnown;
702
2
  CHECK_LE(cipher->auth_tag_len_, sizeof(cipher->auth_tag_));
703
704
2
  memset(cipher->auth_tag_, 0, sizeof(cipher->auth_tag_));
705
2
  auth_tag.CopyTo(cipher->auth_tag_, cipher->auth_tag_len_);
706
707
2
  args.GetReturnValue().Set(true);
708
2
}
709
710
6
bool CipherBase::MaybePassAuthTagToOpenSSL() {
711
6
  if (auth_tag_state_ == kAuthTagKnown) {
712
2
    if (!EVP_CIPHER_CTX_ctrl(ctx_.get(),
713
2
                             EVP_CTRL_AEAD_SET_TAG,
714
2
                             auth_tag_len_,
715
2
                             reinterpret_cast<unsigned char*>(auth_tag_))) {
716
0
      return false;
717
0
    }
718
2
    auth_tag_state_ = kAuthTagPassedToOpenSSL;
719
2
  }
720
6
  return true;
721
6
}
722
723
bool CipherBase::SetAAD(
724
    const ArrayBufferOrViewContents<unsigned char>& data,
725
4
    int plaintext_len) {
726
4
  if (!ctx_ || !IsAuthenticatedMode())
727
0
    return false;
728
4
  MarkPopErrorOnReturn mark_pop_error_on_return;
729
730
4
  int outlen;
731
4
  const int mode = EVP_CIPHER_CTX_mode(ctx_.get());
732
733
  // When in CCM mode, we need to set the authentication tag and the plaintext
734
  // length in advance.
735
4
  if (mode == EVP_CIPH_CCM_MODE) {
736
4
    if (plaintext_len < 0) {
737
0
      THROW_ERR_MISSING_ARGS(env(),
738
0
          "options.plaintextLength required for CCM mode with AAD");
739
0
      return false;
740
0
    }
741
742
4
    if (!CheckCCMMessageLength(plaintext_len))
743
0
      return false;
744
745
4
    if (kind_ == kDecipher) {
746
2
      if (!MaybePassAuthTagToOpenSSL())
747
0
        return false;
748
2
    }
749
750
    // Specify the plaintext length.
751
4
    if (!EVP_CipherUpdate(ctx_.get(), nullptr, &outlen, nullptr, plaintext_len))
752
0
      return false;
753
4
  }
754
755
4
  return 1 == EVP_CipherUpdate(ctx_.get(),
756
4
                               nullptr,
757
4
                               &outlen,
758
4
                               data.data(),
759
4
                               data.size());
760
4
}
761
762
4
void CipherBase::SetAAD(const FunctionCallbackInfo<Value>& args) {
763
4
  CipherBase* cipher;
764
4
  ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder());
765
4
  Environment* env = Environment::GetCurrent(args);
766
767
4
  CHECK_EQ(args.Length(), 2);
768
4
  CHECK(args[1]->IsInt32());
769
4
  int plaintext_len = args[1].As<Int32>()->Value();
770
4
  ArrayBufferOrViewContents<unsigned char> buf(args[0]);
771
772
4
  if (UNLIKELY(!buf.CheckSizeInt32()))
773
0
    return THROW_ERR_OUT_OF_RANGE(env, "buffer is too big");
774
4
  args.GetReturnValue().Set(cipher->SetAAD(buf, plaintext_len));
775
4
}
776
777
CipherBase::UpdateResult CipherBase::Update(
778
    const char* data,
779
    size_t len,
780
7
    std::unique_ptr<BackingStore>* out) {
781
7
  if (!ctx_ || len > INT_MAX)
782
0
    return kErrorState;
783
7
  MarkPopErrorOnReturn mark_pop_error_on_return;
784
785
7
  const int mode = EVP_CIPHER_CTX_mode(ctx_.get());
786
787
7
  if (mode == EVP_CIPH_CCM_MODE && !CheckCCMMessageLength(len))
788
0
    return kErrorMessageSize;
789
790
  // Pass the authentication tag to OpenSSL if possible. This will only happen
791
  // once, usually on the first update.
792
7
  if (kind_ == kDecipher && IsAuthenticatedMode())
793
2
    CHECK(MaybePassAuthTagToOpenSSL());
794
795
7
  const int block_size = EVP_CIPHER_CTX_block_size(ctx_.get());
796
7
  CHECK_GT(block_size, 0);
797
7
  if (len + block_size > INT_MAX) return kErrorState;
798
7
  int buf_len = len + block_size;
799
800
  // For key wrapping algorithms, get output size by calling
801
  // EVP_CipherUpdate() with null output.
802
7
  if (kind_ == kCipher && mode == EVP_CIPH_WRAP_MODE &&
803
7
      EVP_CipherUpdate(ctx_.get(),
804
0
                       nullptr,
805
0
                       &buf_len,
806
0
                       reinterpret_cast<const unsigned char*>(data),
807
0
                       len) != 1) {
808
0
    return kErrorState;
809
0
  }
810
811
7
  {
812
7
    NoArrayBufferZeroFillScope no_zero_fill_scope(env()->isolate_data());
813
7
    *out = ArrayBuffer::NewBackingStore(env()->isolate(), buf_len);
814
7
  }
815
816
7
  int r = EVP_CipherUpdate(ctx_.get(),
817
7
                           static_cast<unsigned char*>((*out)->Data()),
818
7
                           &buf_len,
819
7
                           reinterpret_cast<const unsigned char*>(data),
820
7
                           len);
821
822
7
  CHECK_LE(static_cast<size_t>(buf_len), (*out)->ByteLength());
823
7
  if (buf_len == 0) {
824
0
    *out = ArrayBuffer::NewBackingStore(env()->isolate(), 0);
825
7
  } else if (static_cast<size_t>(buf_len) != (*out)->ByteLength()) {
826
7
    std::unique_ptr<BackingStore> old_out = std::move(*out);
827
7
    *out = ArrayBuffer::NewBackingStore(env()->isolate(), buf_len);
828
7
    memcpy(static_cast<char*>((*out)->Data()),
829
7
           static_cast<char*>(old_out->Data()),
830
7
           buf_len);
831
7
  }
832
833
  // When in CCM mode, EVP_CipherUpdate will fail if the authentication tag is
834
  // invalid. In that case, remember the error and throw in final().
835
7
  if (!r && kind_ == kDecipher && mode == EVP_CIPH_CCM_MODE) {
836
0
    pending_auth_failed_ = true;
837
0
    return kSuccess;
838
0
  }
839
7
  return r == 1 ? kSuccess : kErrorState;
840
7
}
841
842
7
void CipherBase::Update(const FunctionCallbackInfo<Value>& args) {
843
7
  Decode<CipherBase>(args, [](CipherBase* cipher,
844
7
                              const FunctionCallbackInfo<Value>& args,
845
7
                              const char* data, size_t size) {
846
7
    std::unique_ptr<BackingStore> out;
847
7
    Environment* env = Environment::GetCurrent(args);
848
849
7
    if (UNLIKELY(size > INT_MAX))
850
0
      return THROW_ERR_OUT_OF_RANGE(env, "data is too long");
851
852
7
    UpdateResult r = cipher->Update(data, size, &out);
853
854
7
    if (r != kSuccess) {
855
0
      if (r == kErrorState) {
856
0
        ThrowCryptoError(env, ERR_get_error(),
857
0
                         "Trying to add data in unsupported state");
858
0
      }
859
0
      return;
860
0
    }
861
862
7
    Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(out));
863
7
    args.GetReturnValue().Set(
864
7
        Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>()));
865
7
  });
866
7
}
867
868
0
bool CipherBase::SetAutoPadding(bool auto_padding) {
869
0
  if (!ctx_)
870
0
    return false;
871
0
  MarkPopErrorOnReturn mark_pop_error_on_return;
872
0
  return EVP_CIPHER_CTX_set_padding(ctx_.get(), auto_padding);
873
0
}
874
875
0
void CipherBase::SetAutoPadding(const FunctionCallbackInfo<Value>& args) {
876
0
  CipherBase* cipher;
877
0
  ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder());
878
879
0
  bool b = cipher->SetAutoPadding(args.Length() < 1 || args[0]->IsTrue());
880
0
  args.GetReturnValue().Set(b);  // Possibly report invalid state failure
881
0
}
882
883
7
bool CipherBase::Final(std::unique_ptr<BackingStore>* out) {
884
7
  if (!ctx_)
885
0
    return false;
886
887
7
  const int mode = EVP_CIPHER_CTX_mode(ctx_.get());
888
889
7
  {
890
7
    NoArrayBufferZeroFillScope no_zero_fill_scope(env()->isolate_data());
891
7
    *out = ArrayBuffer::NewBackingStore(env()->isolate(),
892
7
        static_cast<size_t>(EVP_CIPHER_CTX_block_size(ctx_.get())));
893
7
  }
894
895
7
  if (kind_ == kDecipher && IsSupportedAuthenticatedMode(ctx_.get()))
896
2
    MaybePassAuthTagToOpenSSL();
897
898
  // OpenSSL v1.x doesn't verify the presence of the auth tag so do
899
  // it ourselves, see https://github.com/nodejs/node/issues/45874.
900
7
  if (OPENSSL_VERSION_NUMBER < 0x30000000L && kind_ == kDecipher &&
901
7
      NID_chacha20_poly1305 == EVP_CIPHER_CTX_nid(ctx_.get()) &&
902
7
      auth_tag_state_ != kAuthTagPassedToOpenSSL) {
903
0
    return false;
904
0
  }
905
906
  // In CCM mode, final() only checks whether authentication failed in update().
907
  // EVP_CipherFinal_ex must not be called and will fail.
908
7
  bool ok;
909
7
  if (kind_ == kDecipher && mode == EVP_CIPH_CCM_MODE) {
910
2
    ok = !pending_auth_failed_;
911
2
    *out = ArrayBuffer::NewBackingStore(env()->isolate(), 0);
912
5
  } else {
913
5
    int out_len = (*out)->ByteLength();
914
5
    ok = EVP_CipherFinal_ex(ctx_.get(),
915
5
                            static_cast<unsigned char*>((*out)->Data()),
916
5
                            &out_len) == 1;
917
918
5
    CHECK_LE(static_cast<size_t>(out_len), (*out)->ByteLength());
919
5
    if (out_len == 0) {
920
3
      *out = ArrayBuffer::NewBackingStore(env()->isolate(), 0);
921
3
    } else if (static_cast<size_t>(out_len) != (*out)->ByteLength()) {
922
2
      std::unique_ptr<BackingStore> old_out = std::move(*out);
923
2
      *out = ArrayBuffer::NewBackingStore(env()->isolate(), out_len);
924
2
      memcpy(static_cast<char*>((*out)->Data()),
925
2
             static_cast<char*>(old_out->Data()),
926
2
             out_len);
927
2
    }
928
929
5
    if (ok && kind_ == kCipher && IsAuthenticatedMode()) {
930
      // In GCM mode, the authentication tag length can be specified in advance,
931
      // but defaults to 16 bytes when encrypting. In CCM and OCB mode, it must
932
      // always be given by the user.
933
2
      if (auth_tag_len_ == kNoAuthTagLength) {
934
0
        CHECK(mode == EVP_CIPH_GCM_MODE);
935
0
        auth_tag_len_ = sizeof(auth_tag_);
936
0
      }
937
2
      ok = (1 == EVP_CIPHER_CTX_ctrl(ctx_.get(), EVP_CTRL_AEAD_GET_TAG,
938
2
                     auth_tag_len_,
939
2
                     reinterpret_cast<unsigned char*>(auth_tag_)));
940
2
    }
941
5
  }
942
943
7
  ctx_.reset();
944
945
7
  return ok;
946
7
}
947
948
7
void CipherBase::Final(const FunctionCallbackInfo<Value>& args) {
949
7
  Environment* env = Environment::GetCurrent(args);
950
951
7
  CipherBase* cipher;
952
7
  ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder());
953
7
  if (cipher->ctx_ == nullptr)
954
0
    return THROW_ERR_CRYPTO_INVALID_STATE(env);
955
956
7
  std::unique_ptr<BackingStore> out;
957
958
  // Check IsAuthenticatedMode() first, Final() destroys the EVP_CIPHER_CTX.
959
7
  const bool is_auth_mode = cipher->IsAuthenticatedMode();
960
7
  bool r = cipher->Final(&out);
961
962
7
  if (!r) {
963
1
    const char* msg = is_auth_mode
964
1
                          ? "Unsupported state or unable to authenticate data"
965
1
                          : "Unsupported state";
966
967
1
    return ThrowCryptoError(env, ERR_get_error(), msg);
968
1
  }
969
970
6
  Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(out));
971
6
  args.GetReturnValue().Set(
972
6
      Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>()));
973
6
}
974
975
template <PublicKeyCipher::Operation operation,
976
          PublicKeyCipher::EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
977
          PublicKeyCipher::EVP_PKEY_cipher_t EVP_PKEY_cipher>
978
bool PublicKeyCipher::Cipher(
979
    Environment* env,
980
    const ManagedEVPPKey& pkey,
981
    int padding,
982
    const EVP_MD* digest,
983
    const ArrayBufferOrViewContents<unsigned char>& oaep_label,
984
    const ArrayBufferOrViewContents<unsigned char>& data,
985
0
    std::unique_ptr<BackingStore>* out) {
986
0
  EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
987
0
  if (!ctx)
988
0
    return false;
989
0
  if (EVP_PKEY_cipher_init(ctx.get()) <= 0)
990
0
    return false;
991
0
  if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), padding) <= 0)
992
0
    return false;
993
994
0
  if (digest != nullptr) {
995
0
    if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx.get(), digest) <= 0)
996
0
      return false;
997
0
  }
998
999
0
  if (!SetRsaOaepLabel(ctx, oaep_label.ToByteSource())) return false;
1000
1001
0
  size_t out_len = 0;
1002
0
  if (EVP_PKEY_cipher(
1003
0
          ctx.get(),
1004
0
          nullptr,
1005
0
          &out_len,
1006
0
          data.data(),
1007
0
          data.size()) <= 0) {
1008
0
    return false;
1009
0
  }
1010
1011
0
  {
1012
0
    NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
1013
0
    *out = ArrayBuffer::NewBackingStore(env->isolate(), out_len);
1014
0
  }
1015
1016
0
  if (EVP_PKEY_cipher(
1017
0
          ctx.get(),
1018
0
          static_cast<unsigned char*>((*out)->Data()),
1019
0
          &out_len,
1020
0
          data.data(),
1021
0
          data.size()) <= 0) {
1022
0
    return false;
1023
0
  }
1024
1025
0
  CHECK_LE(out_len, (*out)->ByteLength());
1026
0
  if (out_len == 0) {
1027
0
    *out = ArrayBuffer::NewBackingStore(env->isolate(), 0);
1028
0
  } else if (out_len != (*out)->ByteLength()) {
1029
0
    std::unique_ptr<BackingStore> old_out = std::move(*out);
1030
0
    *out = ArrayBuffer::NewBackingStore(env->isolate(), out_len);
1031
0
    memcpy(static_cast<char*>((*out)->Data()),
1032
0
           static_cast<char*>(old_out->Data()),
1033
0
           out_len);
1034
0
  }
1035
1036
0
  return true;
1037
0
}
Unexecuted instantiation: bool node::crypto::PublicKeyCipher::Cipher<(node::crypto::PublicKeyCipher::Operation)0, &EVP_PKEY_encrypt_init, &EVP_PKEY_encrypt>(node::Environment*, node::crypto::ManagedEVPPKey const&, int, evp_md_st const*, node::crypto::ArrayBufferOrViewContents<unsigned char> const&, node::crypto::ArrayBufferOrViewContents<unsigned char> const&, std::__1::unique_ptr<v8::BackingStore, std::__1::default_delete<v8::BackingStore> >*)
Unexecuted instantiation: bool node::crypto::PublicKeyCipher::Cipher<(node::crypto::PublicKeyCipher::Operation)1, &EVP_PKEY_decrypt_init, &EVP_PKEY_decrypt>(node::Environment*, node::crypto::ManagedEVPPKey const&, int, evp_md_st const*, node::crypto::ArrayBufferOrViewContents<unsigned char> const&, node::crypto::ArrayBufferOrViewContents<unsigned char> const&, std::__1::unique_ptr<v8::BackingStore, std::__1::default_delete<v8::BackingStore> >*)
Unexecuted instantiation: bool node::crypto::PublicKeyCipher::Cipher<(node::crypto::PublicKeyCipher::Operation)1, &EVP_PKEY_sign_init, &EVP_PKEY_sign>(node::Environment*, node::crypto::ManagedEVPPKey const&, int, evp_md_st const*, node::crypto::ArrayBufferOrViewContents<unsigned char> const&, node::crypto::ArrayBufferOrViewContents<unsigned char> const&, std::__1::unique_ptr<v8::BackingStore, std::__1::default_delete<v8::BackingStore> >*)
Unexecuted instantiation: bool node::crypto::PublicKeyCipher::Cipher<(node::crypto::PublicKeyCipher::Operation)0, &EVP_PKEY_verify_recover_init, &EVP_PKEY_verify_recover>(node::Environment*, node::crypto::ManagedEVPPKey const&, int, evp_md_st const*, node::crypto::ArrayBufferOrViewContents<unsigned char> const&, node::crypto::ArrayBufferOrViewContents<unsigned char> const&, std::__1::unique_ptr<v8::BackingStore, std::__1::default_delete<v8::BackingStore> >*)
1038
1039
template <PublicKeyCipher::Operation operation,
1040
          PublicKeyCipher::EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
1041
          PublicKeyCipher::EVP_PKEY_cipher_t EVP_PKEY_cipher>
1042
0
void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
1043
0
  MarkPopErrorOnReturn mark_pop_error_on_return;
1044
0
  Environment* env = Environment::GetCurrent(args);
1045
1046
0
  unsigned int offset = 0;
1047
0
  ManagedEVPPKey pkey =
1048
0
      ManagedEVPPKey::GetPublicOrPrivateKeyFromJs(args, &offset);
1049
0
  if (!pkey)
1050
0
    return;
1051
1052
0
  ArrayBufferOrViewContents<unsigned char> buf(args[offset]);
1053
0
  if (UNLIKELY(!buf.CheckSizeInt32()))
1054
0
    return THROW_ERR_OUT_OF_RANGE(env, "buffer is too long");
1055
1056
0
  uint32_t padding;
1057
0
  if (!args[offset + 1]->Uint32Value(env->context()).To(&padding)) return;
1058
1059
0
  if (EVP_PKEY_cipher == EVP_PKEY_decrypt &&
1060
0
      operation == PublicKeyCipher::kPrivate && padding == RSA_PKCS1_PADDING) {
1061
0
    EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
1062
0
    CHECK(ctx);
1063
1064
0
    if (EVP_PKEY_decrypt_init(ctx.get()) <= 0) {
1065
0
      return ThrowCryptoError(env, ERR_get_error());
1066
0
    }
1067
1068
0
    int rsa_pkcs1_implicit_rejection =
1069
0
        EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_pkcs1_implicit_rejection", "1");
1070
    // From the doc -2 means that the option is not supported.
1071
    // The default for the option is enabled and if it has been
1072
    // specifically disabled we want to respect that so we will
1073
    // not throw an error if the option is supported regardless
1074
    // of how it is set. The call to set the value
1075
    // will not affect what is used since a different context is
1076
    // used in the call if the option is supported
1077
0
    if (rsa_pkcs1_implicit_rejection <= 0) {
1078
0
      return THROW_ERR_INVALID_ARG_VALUE(
1079
0
          env,
1080
0
          "RSA_PKCS1_PADDING is no longer supported for private decryption,"
1081
0
          " this can be reverted with --security-revert=CVE-2024-PEND");
1082
0
    }
1083
0
  }
1084
1085
0
  const EVP_MD* digest = nullptr;
1086
0
  if (args[offset + 2]->IsString()) {
1087
0
    const Utf8Value oaep_str(env->isolate(), args[offset + 2]);
1088
0
    digest = EVP_get_digestbyname(*oaep_str);
1089
0
    if (digest == nullptr)
1090
0
      return THROW_ERR_OSSL_EVP_INVALID_DIGEST(env);
1091
0
  }
1092
1093
0
  ArrayBufferOrViewContents<unsigned char> oaep_label(
1094
0
      !args[offset + 3]->IsUndefined() ? args[offset + 3] : Local<Value>());
1095
0
  if (UNLIKELY(!oaep_label.CheckSizeInt32()))
1096
0
    return THROW_ERR_OUT_OF_RANGE(env, "oaepLabel is too big");
1097
1098
0
  std::unique_ptr<BackingStore> out;
1099
0
  if (!Cipher<operation, EVP_PKEY_cipher_init, EVP_PKEY_cipher>(
1100
0
          env, pkey, padding, digest, oaep_label, buf, &out)) {
1101
0
    return ThrowCryptoError(env, ERR_get_error());
1102
0
  }
1103
1104
0
  Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(out));
1105
0
  args.GetReturnValue().Set(
1106
0
      Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>()));
1107
0
}
Unexecuted instantiation: void node::crypto::PublicKeyCipher::Cipher<(node::crypto::PublicKeyCipher::Operation)0, &EVP_PKEY_encrypt_init, &EVP_PKEY_encrypt>(v8::FunctionCallbackInfo<v8::Value> const&)
Unexecuted instantiation: void node::crypto::PublicKeyCipher::Cipher<(node::crypto::PublicKeyCipher::Operation)1, &EVP_PKEY_decrypt_init, &EVP_PKEY_decrypt>(v8::FunctionCallbackInfo<v8::Value> const&)
Unexecuted instantiation: void node::crypto::PublicKeyCipher::Cipher<(node::crypto::PublicKeyCipher::Operation)1, &EVP_PKEY_sign_init, &EVP_PKEY_sign>(v8::FunctionCallbackInfo<v8::Value> const&)
Unexecuted instantiation: void node::crypto::PublicKeyCipher::Cipher<(node::crypto::PublicKeyCipher::Operation)0, &EVP_PKEY_verify_recover_init, &EVP_PKEY_verify_recover>(v8::FunctionCallbackInfo<v8::Value> const&)
1108
1109
}  // namespace crypto
1110
}  // namespace node