GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_rsa.cc Lines: 254 311 81.7 %
Date: 2022-10-31 03:21:21 Branches: 189 322 58.7 %

Line Branch Exec Source
1
#include "crypto/crypto_rsa.h"
2
#include "async_wrap-inl.h"
3
#include "base_object-inl.h"
4
#include "crypto/crypto_bio.h"
5
#include "crypto/crypto_keys.h"
6
#include "crypto/crypto_util.h"
7
#include "env-inl.h"
8
#include "memory_tracker-inl.h"
9
#include "threadpoolwork-inl.h"
10
#include "v8.h"
11
12
#include <openssl/bn.h>
13
#include <openssl/rsa.h>
14
15
namespace node {
16
17
using v8::ArrayBuffer;
18
using v8::BackingStore;
19
using v8::FunctionCallbackInfo;
20
using v8::Int32;
21
using v8::Just;
22
using v8::Local;
23
using v8::Maybe;
24
using v8::Nothing;
25
using v8::Number;
26
using v8::Object;
27
using v8::String;
28
using v8::Uint32;
29
using v8::Value;
30
31
namespace crypto {
32
408
EVPKeyCtxPointer RsaKeyGenTraits::Setup(RsaKeyPairGenConfig* params) {
33
  EVPKeyCtxPointer ctx(
34
      EVP_PKEY_CTX_new_id(
35
408
          params->params.variant == kKeyVariantRSA_PSS
36
              ? EVP_PKEY_RSA_PSS
37
              : EVP_PKEY_RSA,
38
816
          nullptr));
39
40
408
  if (EVP_PKEY_keygen_init(ctx.get()) <= 0)
41
    return EVPKeyCtxPointer();
42
43
408
  if (EVP_PKEY_CTX_set_rsa_keygen_bits(
44
          ctx.get(),
45
816
          params->params.modulus_bits) <= 0) {
46
    return EVPKeyCtxPointer();
47
  }
48
49
  // 0x10001 is the default RSA exponent.
50
408
  if (params->params.exponent != 0x10001) {
51
97
    BignumPointer bn(BN_new());
52
97
    CHECK_NOT_NULL(bn.get());
53
97
    CHECK(BN_set_word(bn.get(), params->params.exponent));
54
    // EVP_CTX accepts ownership of bn on success.
55
97
    if (EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx.get(), bn.get()) <= 0)
56
      return EVPKeyCtxPointer();
57
58
97
    bn.release();
59
  }
60
61
408
  if (params->params.variant == kKeyVariantRSA_PSS) {
62

13
    if (params->params.md != nullptr &&
63
6
        EVP_PKEY_CTX_set_rsa_pss_keygen_md(ctx.get(), params->params.md) <= 0) {
64
      return EVPKeyCtxPointer();
65
    }
66
67
    // TODO(tniessen): This appears to only be necessary in OpenSSL 3, while
68
    // OpenSSL 1.1.1 behaves as recommended by RFC 8017 and defaults the MGF1
69
    // hash algorithm to the RSA-PSS hashAlgorithm. Remove this code if the
70
    // behavior of OpenSSL 3 changes.
71
7
    const EVP_MD* mgf1_md = params->params.mgf1_md;
72

7
    if (mgf1_md == nullptr && params->params.md != nullptr) {
73
3
      mgf1_md = params->params.md;
74
    }
75
76

13
    if (mgf1_md != nullptr &&
77
6
        EVP_PKEY_CTX_set_rsa_pss_keygen_mgf1_md(
78
            ctx.get(),
79
            mgf1_md) <= 0) {
80
      return EVPKeyCtxPointer();
81
    }
82
83
7
    int saltlen = params->params.saltlen;
84

7
    if (saltlen < 0 && params->params.md != nullptr) {
85
1
      saltlen = EVP_MD_size(params->params.md);
86
    }
87
88

13
    if (saltlen >= 0 &&
89
6
        EVP_PKEY_CTX_set_rsa_pss_keygen_saltlen(
90
            ctx.get(),
91
            saltlen) <= 0) {
92
      return EVPKeyCtxPointer();
93
    }
94
  }
95
96
408
  return ctx;
97
}
98
99
// Input parameters to the RsaKeyGenJob:
100
// For key variants RSA-OAEP and RSA-SSA-PKCS1-v1_5
101
//   1. CryptoJobMode
102
//   2. Key Variant
103
//   3. Modulus Bits
104
//   4. Public Exponent
105
//   5. Public Format
106
//   6. Public Type
107
//   7. Private Format
108
//   8. Private Type
109
//   9. Cipher
110
//   10. Passphrase
111
//
112
// For RSA-PSS variant
113
//   1. CryptoJobMode
114
//   2. Key Variant
115
//   3. Modulus Bits
116
//   4. Public Exponent
117
//   5. Digest
118
//   6. mgf1 Digest
119
//   7. Salt length
120
//   8. Public Format
121
//   9. Public Type
122
//   10. Private Format
123
//   11. Private Type
124
//   12. Cipher
125
//   13. Passphrase
126
411
Maybe<bool> RsaKeyGenTraits::AdditionalConfig(
127
    CryptoJobMode mode,
128
    const FunctionCallbackInfo<Value>& args,
129
    unsigned int* offset,
130
    RsaKeyPairGenConfig* params) {
131
411
  Environment* env = Environment::GetCurrent(args);
132
133

822
  CHECK(args[*offset]->IsUint32());  // Variant
134

822
  CHECK(args[*offset + 1]->IsUint32());  // Modulus bits
135

822
  CHECK(args[*offset + 2]->IsUint32());  // Exponent
136
137
411
  params->params.variant =
138
1233
      static_cast<RSAKeyVariant>(args[*offset].As<Uint32>()->Value());
139
140

813
  CHECK_IMPLIES(params->params.variant != kKeyVariantRSA_PSS,
141
                args.Length() == 10);
142

420
  CHECK_IMPLIES(params->params.variant == kKeyVariantRSA_PSS,
143
                args.Length() == 13);
144
145
1233
  params->params.modulus_bits = args[*offset + 1].As<Uint32>()->Value();
146
1233
  params->params.exponent = args[*offset + 2].As<Uint32>()->Value();
147
148
411
  *offset += 3;
149
150
411
  if (params->params.variant == kKeyVariantRSA_PSS) {
151

27
    if (!args[*offset]->IsUndefined()) {
152

21
      CHECK(args[*offset]->IsString());
153
14
      Utf8Value digest(env->isolate(), args[*offset]);
154
7
      params->params.md = EVP_get_digestbyname(*digest);
155
7
      if (params->params.md == nullptr) {
156
1
        THROW_ERR_CRYPTO_INVALID_DIGEST(env, "Invalid digest: %s", *digest);
157
1
        return Nothing<bool>();
158
      }
159
    }
160
161

24
    if (!args[*offset + 1]->IsUndefined()) {
162

12
      CHECK(args[*offset + 1]->IsString());
163
8
      Utf8Value digest(env->isolate(), args[*offset + 1]);
164
4
      params->params.mgf1_md = EVP_get_digestbyname(*digest);
165
4
      if (params->params.mgf1_md == nullptr) {
166
1
        THROW_ERR_CRYPTO_INVALID_DIGEST(
167
1
            env, "Invalid MGF1 digest: %s", *digest);
168
1
        return Nothing<bool>();
169
      }
170
    }
171
172

21
    if (!args[*offset + 2]->IsUndefined()) {
173

10
      CHECK(args[*offset + 2]->IsInt32());
174
15
      params->params.saltlen = args[*offset + 2].As<Int32>()->Value();
175
5
      if (params->params.saltlen < 0) {
176
        THROW_ERR_OUT_OF_RANGE(
177
          env,
178
          "salt length is out of range");
179
        return Nothing<bool>();
180
      }
181
    }
182
183
7
    *offset += 3;
184
  }
185
186
409
  return Just(true);
187
}
188
189
namespace {
190
WebCryptoKeyExportStatus RSA_JWK_Export(
191
    KeyObjectData* key_data,
192
    const RSAKeyExportConfig& params,
193
    ByteSource* out) {
194
  return WebCryptoKeyExportStatus::FAILED;
195
}
196
197
template <PublicKeyCipher::EVP_PKEY_cipher_init_t init,
198
          PublicKeyCipher::EVP_PKEY_cipher_t cipher>
199
714
WebCryptoCipherStatus RSA_Cipher(
200
    Environment* env,
201
    KeyObjectData* key_data,
202
    const RSACipherConfig& params,
203
    const ByteSource& in,
204
    ByteSource* out) {
205
714
  CHECK_NE(key_data->GetKeyType(), kKeyTypeSecret);
206
1428
  ManagedEVPPKey m_pkey = key_data->GetAsymmetricKey();
207
1428
  Mutex::ScopedLock lock(*m_pkey.mutex());
208
209
1428
  EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(m_pkey.get(), nullptr));
210
211

714
  if (!ctx || init(ctx.get()) <= 0)
212
    return WebCryptoCipherStatus::FAILED;
213
214
714
  if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), params.padding) <= 0) {
215
    return WebCryptoCipherStatus::FAILED;
216
  }
217
218

2142
  if (params.digest != nullptr &&
219
1428
      (EVP_PKEY_CTX_set_rsa_oaep_md(ctx.get(), params.digest) <= 0 ||
220
714
       EVP_PKEY_CTX_set_rsa_mgf1_md(ctx.get(), params.digest) <= 0)) {
221
    return WebCryptoCipherStatus::FAILED;
222
  }
223
224
714
  if (!SetRsaOaepLabel(ctx, params.label)) return WebCryptoCipherStatus::FAILED;
225
226
714
  size_t out_len = 0;
227
714
  if (cipher(
228
          ctx.get(),
229
          nullptr,
230
          &out_len,
231
          in.data<unsigned char>(),
232
714
          in.size()) <= 0) {
233
    return WebCryptoCipherStatus::FAILED;
234
  }
235
236
1428
  ByteSource::Builder buf(out_len);
237
238
714
  if (cipher(ctx.get(),
239
             buf.data<unsigned char>(),
240
             &out_len,
241
             in.data<unsigned char>(),
242
714
             in.size()) <= 0) {
243
48
    return WebCryptoCipherStatus::FAILED;
244
  }
245
246
666
  *out = std::move(buf).release(out_len);
247
666
  return WebCryptoCipherStatus::OK;
248
}
249
}  // namespace
250
251
347
Maybe<bool> RSAKeyExportTraits::AdditionalConfig(
252
    const FunctionCallbackInfo<Value>& args,
253
    unsigned int offset,
254
    RSAKeyExportConfig* params) {
255

694
  CHECK(args[offset]->IsUint32());  // RSAKeyVariant
256
347
  params->variant =
257
1041
      static_cast<RSAKeyVariant>(args[offset].As<Uint32>()->Value());
258
347
  return Just(true);
259
}
260
261
347
WebCryptoKeyExportStatus RSAKeyExportTraits::DoExport(
262
    std::shared_ptr<KeyObjectData> key_data,
263
    WebCryptoKeyFormat format,
264
    const RSAKeyExportConfig& params,
265
    ByteSource* out) {
266
347
  CHECK_NE(key_data->GetKeyType(), kKeyTypeSecret);
267
268

347
  switch (format) {
269
    case kWebCryptoKeyFormatRaw:
270
      // Not supported for RSA keys of either type
271
      return WebCryptoKeyExportStatus::FAILED;
272
    case kWebCryptoKeyFormatJWK:
273
      return RSA_JWK_Export(key_data.get(), params, out);
274
172
    case kWebCryptoKeyFormatPKCS8:
275
172
      if (key_data->GetKeyType() != kKeyTypePrivate)
276
        return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
277
172
      return PKEY_PKCS8_Export(key_data.get(), out);
278
175
    case kWebCryptoKeyFormatSPKI:
279
175
      if (key_data->GetKeyType() != kKeyTypePublic)
280
        return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
281
175
      return PKEY_SPKI_Export(key_data.get(), out);
282
    default:
283
      UNREACHABLE();
284
  }
285
}
286
287
357
RSACipherConfig::RSACipherConfig(RSACipherConfig&& other) noexcept
288
357
    : mode(other.mode),
289
357
      label(std::move(other.label)),
290
357
      padding(other.padding),
291
357
      digest(other.digest) {}
292
293
void RSACipherConfig::MemoryInfo(MemoryTracker* tracker) const {
294
  if (mode == kCryptoJobAsync)
295
    tracker->TrackFieldWithSize("label", label.size());
296
}
297
298
357
Maybe<bool> RSACipherTraits::AdditionalConfig(
299
    CryptoJobMode mode,
300
    const FunctionCallbackInfo<Value>& args,
301
    unsigned int offset,
302
    WebCryptoCipherMode cipher_mode,
303
    RSACipherConfig* params) {
304
357
  Environment* env = Environment::GetCurrent(args);
305
306
357
  params->mode = mode;
307
357
  params->padding = RSA_PKCS1_OAEP_PADDING;
308
309

714
  CHECK(args[offset]->IsUint32());
310
  RSAKeyVariant variant =
311
1071
      static_cast<RSAKeyVariant>(args[offset].As<Uint32>()->Value());
312
313
357
  switch (variant) {
314
357
    case kKeyVariantRSA_OAEP: {
315

1071
      CHECK(args[offset + 1]->IsString());  // digest
316
714
      Utf8Value digest(env->isolate(), args[offset + 1]);
317
318
357
      params->digest = EVP_get_digestbyname(*digest);
319
357
      if (params->digest == nullptr) {
320
        THROW_ERR_CRYPTO_INVALID_DIGEST(env, "Invalid digest: %s", *digest);
321
        return Nothing<bool>();
322
      }
323
324

714
      if (IsAnyByteSource(args[offset + 2])) {
325
586
        ArrayBufferOrViewContents<char> label(args[offset + 2]);
326
293
        if (UNLIKELY(!label.CheckSizeInt32())) {
327
          THROW_ERR_OUT_OF_RANGE(env, "label is too big");
328
          return Nothing<bool>();
329
        }
330
293
        params->label = label.ToCopy();
331
      }
332
357
      break;
333
    }
334
    default:
335
      THROW_ERR_CRYPTO_INVALID_KEYTYPE(env);
336
      return Nothing<bool>();
337
  }
338
339
357
  return Just(true);
340
}
341
342
357
WebCryptoCipherStatus RSACipherTraits::DoCipher(
343
    Environment* env,
344
    std::shared_ptr<KeyObjectData> key_data,
345
    WebCryptoCipherMode cipher_mode,
346
    const RSACipherConfig& params,
347
    const ByteSource& in,
348
    ByteSource* out) {
349
357
  switch (cipher_mode) {
350
175
    case kWebCryptoCipherEncrypt:
351
175
      CHECK_EQ(key_data->GetKeyType(), kKeyTypePublic);
352
175
      return RSA_Cipher<EVP_PKEY_encrypt_init, EVP_PKEY_encrypt>(
353
175
          env, key_data.get(), params, in, out);
354
182
    case kWebCryptoCipherDecrypt:
355
182
      CHECK_EQ(key_data->GetKeyType(), kKeyTypePrivate);
356
182
      return RSA_Cipher<EVP_PKEY_decrypt_init, EVP_PKEY_decrypt>(
357
182
          env, key_data.get(), params, in, out);
358
  }
359
  return WebCryptoCipherStatus::FAILED;
360
}
361
362
409
Maybe<bool> ExportJWKRsaKey(
363
    Environment* env,
364
    std::shared_ptr<KeyObjectData> key,
365
    Local<Object> target) {
366
818
  ManagedEVPPKey m_pkey = key->GetAsymmetricKey();
367
818
  Mutex::ScopedLock lock(*m_pkey.mutex());
368
409
  int type = EVP_PKEY_id(m_pkey.get());
369

409
  CHECK(type == EVP_PKEY_RSA || type == EVP_PKEY_RSA_PSS);
370
371
  // TODO(tniessen): Remove the "else" branch once we drop support for OpenSSL
372
  // versions older than 1.1.1e via FIPS / dynamic linking.
373
  const RSA* rsa;
374
409
  if (OpenSSL_version_num() >= 0x1010105fL) {
375
409
    rsa = EVP_PKEY_get0_RSA(m_pkey.get());
376
  } else {
377
    rsa = static_cast<const RSA*>(EVP_PKEY_get0(m_pkey.get()));
378
  }
379
409
  CHECK_NOT_NULL(rsa);
380
381
  const BIGNUM* n;
382
  const BIGNUM* e;
383
  const BIGNUM* d;
384
  const BIGNUM* p;
385
  const BIGNUM* q;
386
  const BIGNUM* dp;
387
  const BIGNUM* dq;
388
  const BIGNUM* qi;
389
409
  RSA_get0_key(rsa, &n, &e, &d);
390
391
818
  if (target->Set(
392
          env->context(),
393
          env->jwk_kty_string(),
394
1636
          env->jwk_rsa_string()).IsNothing()) {
395
    return Nothing<bool>();
396
  }
397
398
1227
  if (SetEncodedValue(env, target, env->jwk_n_string(), n).IsNothing() ||
399

1227
      SetEncodedValue(env, target, env->jwk_e_string(), e).IsNothing()) {
400
    return Nothing<bool>();
401
  }
402
403
409
  if (key->GetKeyType() == kKeyTypePrivate) {
404
211
    RSA_get0_factors(rsa, &p, &q);
405
211
    RSA_get0_crt_params(rsa, &dp, &dq, &qi);
406
211
    if (SetEncodedValue(env, target, env->jwk_d_string(), d).IsNothing() ||
407
422
        SetEncodedValue(env, target, env->jwk_p_string(), p).IsNothing() ||
408
422
        SetEncodedValue(env, target, env->jwk_q_string(), q).IsNothing() ||
409
422
        SetEncodedValue(env, target, env->jwk_dp_string(), dp).IsNothing() ||
410

844
        SetEncodedValue(env, target, env->jwk_dq_string(), dq).IsNothing() ||
411

633
        SetEncodedValue(env, target, env->jwk_qi_string(), qi).IsNothing()) {
412
      return Nothing<bool>();
413
    }
414
  }
415
416
409
  return Just(true);
417
}
418
419
502
std::shared_ptr<KeyObjectData> ImportJWKRsaKey(
420
    Environment* env,
421
    Local<Object> jwk,
422
    const FunctionCallbackInfo<Value>& args,
423
    unsigned int offset) {
424
  Local<Value> n_value;
425
  Local<Value> e_value;
426
  Local<Value> d_value;
427
428
1004
  if (!jwk->Get(env->context(), env->jwk_n_string()).ToLocal(&n_value) ||
429
1506
      !jwk->Get(env->context(), env->jwk_e_string()).ToLocal(&e_value) ||
430
1506
      !jwk->Get(env->context(), env->jwk_d_string()).ToLocal(&d_value) ||
431

2008
      !n_value->IsString() ||
432
1004
      !e_value->IsString()) {
433
    THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
434
    return std::shared_ptr<KeyObjectData>();
435
  }
436
437

1484
  if (!d_value->IsUndefined() && !d_value->IsString()) {
438
    THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
439
    return std::shared_ptr<KeyObjectData>();
440
  }
441
442
1004
  KeyType type = d_value->IsString() ? kKeyTypePrivate : kKeyTypePublic;
443
444
1004
  RsaPointer rsa(RSA_new());
445
446
1004
  ByteSource n = ByteSource::FromEncodedString(env, n_value.As<String>());
447
1004
  ByteSource e = ByteSource::FromEncodedString(env, e_value.As<String>());
448
449
1004
  if (!RSA_set0_key(
450
          rsa.get(),
451
1004
          n.ToBN().release(),
452
1004
          e.ToBN().release(),
453
          nullptr)) {
454
    THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
455
    return std::shared_ptr<KeyObjectData>();
456
  }
457
458
502
  if (type == kKeyTypePrivate) {
459
    Local<Value> p_value;
460
    Local<Value> q_value;
461
    Local<Value> dp_value;
462
    Local<Value> dq_value;
463
    Local<Value> qi_value;
464
465
480
    if (!jwk->Get(env->context(), env->jwk_p_string()).ToLocal(&p_value) ||
466
720
        !jwk->Get(env->context(), env->jwk_q_string()).ToLocal(&q_value) ||
467
720
        !jwk->Get(env->context(), env->jwk_dp_string()).ToLocal(&dp_value) ||
468

1200
        !jwk->Get(env->context(), env->jwk_dq_string()).ToLocal(&dq_value) ||
469

960
        !jwk->Get(env->context(), env->jwk_qi_string()).ToLocal(&qi_value)) {
470
      THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
471
      return std::shared_ptr<KeyObjectData>();
472
    }
473
474
240
    if (!p_value->IsString() ||
475
480
        !q_value->IsString() ||
476
480
        !dp_value->IsString() ||
477

960
        !dq_value->IsString() ||
478
480
        !qi_value->IsString()) {
479
      THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
480
      return std::shared_ptr<KeyObjectData>();
481
    }
482
483
240
    ByteSource d = ByteSource::FromEncodedString(env, d_value.As<String>());
484
240
    ByteSource q = ByteSource::FromEncodedString(env, q_value.As<String>());
485
240
    ByteSource p = ByteSource::FromEncodedString(env, p_value.As<String>());
486
240
    ByteSource dp = ByteSource::FromEncodedString(env, dp_value.As<String>());
487
240
    ByteSource dq = ByteSource::FromEncodedString(env, dq_value.As<String>());
488
240
    ByteSource qi = ByteSource::FromEncodedString(env, qi_value.As<String>());
489
490

720
    if (!RSA_set0_key(rsa.get(), nullptr, nullptr, d.ToBN().release()) ||
491


960
        !RSA_set0_factors(rsa.get(), p.ToBN().release(), q.ToBN().release()) ||
492
720
        !RSA_set0_crt_params(
493
            rsa.get(),
494
480
            dp.ToBN().release(),
495
480
            dq.ToBN().release(),
496

480
            qi.ToBN().release())) {
497
      THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
498
      return std::shared_ptr<KeyObjectData>();
499
    }
500
  }
501
502
502
  EVPKeyPointer pkey(EVP_PKEY_new());
503
502
  CHECK_EQ(EVP_PKEY_set1_RSA(pkey.get(), rsa.get()), 1);
504
505
502
  return KeyObjectData::CreateAsymmetric(type, ManagedEVPPKey(std::move(pkey)));
506
}
507
508
1697
Maybe<bool> GetRsaKeyDetail(
509
    Environment* env,
510
    std::shared_ptr<KeyObjectData> key,
511
    Local<Object> target) {
512
  const BIGNUM* e;  // Public Exponent
513
  const BIGNUM* n;  // Modulus
514
515
3394
  ManagedEVPPKey m_pkey = key->GetAsymmetricKey();
516
3394
  Mutex::ScopedLock lock(*m_pkey.mutex());
517
1697
  int type = EVP_PKEY_id(m_pkey.get());
518

1697
  CHECK(type == EVP_PKEY_RSA || type == EVP_PKEY_RSA_PSS);
519
520
  // TODO(tniessen): Remove the "else" branch once we drop support for OpenSSL
521
  // versions older than 1.1.1e via FIPS / dynamic linking.
522
  const RSA* rsa;
523
1697
  if (OpenSSL_version_num() >= 0x1010105fL) {
524
1697
    rsa = EVP_PKEY_get0_RSA(m_pkey.get());
525
  } else {
526
    rsa = static_cast<const RSA*>(EVP_PKEY_get0(m_pkey.get()));
527
  }
528
1697
  CHECK_NOT_NULL(rsa);
529
530
1697
  RSA_get0_key(rsa, &n, &e, nullptr);
531
532
1697
  size_t modulus_length = BN_num_bytes(n) * CHAR_BIT;
533
534
1697
  if (target
535
1697
          ->Set(
536
              env->context(),
537
              env->modulus_length_string(),
538
5091
              Number::New(env->isolate(), static_cast<double>(modulus_length)))
539
1697
          .IsNothing()) {
540
    return Nothing<bool>();
541
  }
542
543
1697
  std::unique_ptr<BackingStore> public_exponent;
544
  {
545
1697
    NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
546
    public_exponent =
547
1697
        ArrayBuffer::NewBackingStore(env->isolate(), BN_num_bytes(e));
548
  }
549
1697
  CHECK_EQ(BN_bn2binpad(e,
550
                        static_cast<unsigned char*>(public_exponent->Data()),
551
                        public_exponent->ByteLength()),
552
           static_cast<int>(public_exponent->ByteLength()));
553
554
1697
  if (target
555
1697
          ->Set(env->context(),
556
                env->public_exponent_string(),
557
6788
                ArrayBuffer::New(env->isolate(), std::move(public_exponent)))
558
1697
          .IsNothing()) {
559
    return Nothing<bool>();
560
  }
561
562
1697
  if (type == EVP_PKEY_RSA_PSS) {
563
    // Due to the way ASN.1 encoding works, default values are omitted when
564
    // encoding the data structure. However, there are also RSA-PSS keys for
565
    // which no parameters are set. In that case, the ASN.1 RSASSA-PSS-params
566
    // sequence will be missing entirely and RSA_get0_pss_params will return
567
    // nullptr. If parameters are present but all parameters are set to their
568
    // default values, an empty sequence will be stored in the ASN.1 structure.
569
    // In that case, RSA_get0_pss_params does not return nullptr but all fields
570
    // of the returned RSA_PSS_PARAMS will be set to nullptr.
571
572
20
    const RSA_PSS_PARAMS* params = RSA_get0_pss_params(rsa);
573
20
    if (params != nullptr) {
574
16
      int hash_nid = NID_sha1;
575
16
      int mgf_nid = NID_mgf1;
576
16
      int mgf1_hash_nid = NID_sha1;
577
16
      int64_t salt_length = 20;
578
579
16
      if (params->hashAlgorithm != nullptr) {
580
14
        hash_nid = OBJ_obj2nid(params->hashAlgorithm->algorithm);
581
      }
582
583
16
      if (target
584
16
              ->Set(
585
                  env->context(),
586
                  env->hash_algorithm_string(),
587
48
                  OneByteString(env->isolate(), OBJ_nid2ln(hash_nid)))
588
16
              .IsNothing()) {
589
        return Nothing<bool>();
590
      }
591
592
16
      if (params->maskGenAlgorithm != nullptr) {
593
14
        mgf_nid = OBJ_obj2nid(params->maskGenAlgorithm->algorithm);
594
14
        if (mgf_nid == NID_mgf1) {
595
14
          mgf1_hash_nid = OBJ_obj2nid(params->maskHash->algorithm);
596
        }
597
      }
598
599
      // If, for some reason, the MGF is not MGF1, then the MGF1 hash function
600
      // is intentionally not added to the object.
601
16
      if (mgf_nid == NID_mgf1) {
602
16
        if (target
603
16
                ->Set(
604
                    env->context(),
605
                    env->mgf1_hash_algorithm_string(),
606
48
                    OneByteString(env->isolate(), OBJ_nid2ln(mgf1_hash_nid)))
607
16
                .IsNothing()) {
608
          return Nothing<bool>();
609
        }
610
      }
611
612
16
      if (params->saltLength != nullptr) {
613
12
        if (ASN1_INTEGER_get_int64(&salt_length, params->saltLength) != 1) {
614
          ThrowCryptoError(env, ERR_get_error(), "ASN1_INTEGER_get_in64 error");
615
          return Nothing<bool>();
616
        }
617
      }
618
619
16
      if (target
620
16
              ->Set(
621
                  env->context(),
622
                  env->salt_length_string(),
623
48
                  Number::New(env->isolate(), static_cast<double>(salt_length)))
624
16
              .IsNothing()) {
625
        return Nothing<bool>();
626
      }
627
    }
628
  }
629
630
1697
  return Just<bool>(true);
631
}
632
633
namespace RSAAlg {
634
785
void Initialize(Environment* env, Local<Object> target) {
635
785
  RSAKeyPairGenJob::Initialize(env, target);
636
785
  RSAKeyExportJob::Initialize(env, target);
637
785
  RSACipherJob::Initialize(env, target);
638
639
2355
  NODE_DEFINE_CONSTANT(target, kKeyVariantRSA_SSA_PKCS1_v1_5);
640
2355
  NODE_DEFINE_CONSTANT(target, kKeyVariantRSA_PSS);
641
1570
  NODE_DEFINE_CONSTANT(target, kKeyVariantRSA_OAEP);
642
785
}
643
644
5581
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
645
5581
  RSAKeyPairGenJob::RegisterExternalReferences(registry);
646
5581
  RSAKeyExportJob::RegisterExternalReferences(registry);
647
5581
  RSACipherJob::RegisterExternalReferences(registry);
648
5581
}
649
}  // namespace RSAAlg
650
}  // namespace crypto
651
}  // namespace node