GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_rsa.cc Lines: 254 317 80.1 %
Date: 2022-06-16 04:15:44 Branches: 190 326 58.3 %

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
168
EVPKeyCtxPointer RsaKeyGenTraits::Setup(RsaKeyPairGenConfig* params) {
33
  EVPKeyCtxPointer ctx(
34
      EVP_PKEY_CTX_new_id(
35
168
          params->params.variant == kKeyVariantRSA_PSS
36
              ? EVP_PKEY_RSA_PSS
37
              : EVP_PKEY_RSA,
38
336
          nullptr));
39
40
168
  if (EVP_PKEY_keygen_init(ctx.get()) <= 0)
41
    return EVPKeyCtxPointer();
42
43
168
  if (EVP_PKEY_CTX_set_rsa_keygen_bits(
44
          ctx.get(),
45
336
          params->params.modulus_bits) <= 0) {
46
    return EVPKeyCtxPointer();
47
  }
48
49
  // 0x10001 is the default RSA exponent.
50
168
  if (params->params.exponent != 0x10001) {
51
2
    BignumPointer bn(BN_new());
52
2
    CHECK_NOT_NULL(bn.get());
53
2
    CHECK(BN_set_word(bn.get(), params->params.exponent));
54
    // EVP_CTX accepts ownership of bn on success.
55
2
    if (EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx.get(), bn.get()) <= 0)
56
      return EVPKeyCtxPointer();
57
58
2
    bn.release();
59
  }
60
61
168
  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
168
  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
169
Maybe<bool> RsaKeyGenTraits::AdditionalConfig(
127
    CryptoJobMode mode,
128
    const FunctionCallbackInfo<Value>& args,
129
    unsigned int* offset,
130
    RsaKeyPairGenConfig* params) {
131
169
  Environment* env = Environment::GetCurrent(args);
132
133

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

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

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

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

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

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

18
      CHECK(args[*offset]->IsString());
153
12
      Utf8Value digest(env->isolate(), args[*offset]);
154
6
      params->params.md = EVP_get_digestbyname(*digest);
155
6
      if (params->params.md == nullptr) {
156
        THROW_ERR_CRYPTO_INVALID_DIGEST(env, "md specifies an invalid digest");
157
        return Nothing<bool>();
158
      }
159
    }
160
161

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

9
      CHECK(args[*offset + 1]->IsString());
163
6
      Utf8Value digest(env->isolate(), args[*offset + 1]);
164
3
      params->params.mgf1_md = EVP_get_digestbyname(*digest);
165
3
      if (params->params.mgf1_md == nullptr) {
166
        THROW_ERR_CRYPTO_INVALID_DIGEST(env,
167
          "mgf1_md specifies an invalid digest");
168
        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
169
  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
  size_t label_len = params.label.size();
225
714
  if (label_len > 0) {
226
458
    void* label = OPENSSL_memdup(params.label.data<char>(), label_len);
227
458
    CHECK_NOT_NULL(label);
228
458
    if (EVP_PKEY_CTX_set0_rsa_oaep_label(
229
      ctx.get(),
230
      static_cast<unsigned char*>(label),
231
458
      label_len) <= 0) {
232
      OPENSSL_free(label);
233
      return WebCryptoCipherStatus::FAILED;
234
    }
235
  }
236
237
714
  size_t out_len = 0;
238
714
  if (cipher(
239
          ctx.get(),
240
          nullptr,
241
          &out_len,
242
          in.data<unsigned char>(),
243
714
          in.size()) <= 0) {
244
    return WebCryptoCipherStatus::FAILED;
245
  }
246
247
1428
  ByteSource::Builder buf(out_len);
248
249
714
  if (cipher(ctx.get(),
250
             buf.data<unsigned char>(),
251
             &out_len,
252
             in.data<unsigned char>(),
253
714
             in.size()) <= 0) {
254
48
    return WebCryptoCipherStatus::FAILED;
255
  }
256
257
666
  *out = std::move(buf).release(out_len);
258
666
  return WebCryptoCipherStatus::OK;
259
}
260
}  // namespace
261
262
347
Maybe<bool> RSAKeyExportTraits::AdditionalConfig(
263
    const FunctionCallbackInfo<Value>& args,
264
    unsigned int offset,
265
    RSAKeyExportConfig* params) {
266

694
  CHECK(args[offset]->IsUint32());  // RSAKeyVariant
267
347
  params->variant =
268
1041
      static_cast<RSAKeyVariant>(args[offset].As<Uint32>()->Value());
269
347
  return Just(true);
270
}
271
272
347
WebCryptoKeyExportStatus RSAKeyExportTraits::DoExport(
273
    std::shared_ptr<KeyObjectData> key_data,
274
    WebCryptoKeyFormat format,
275
    const RSAKeyExportConfig& params,
276
    ByteSource* out) {
277
347
  CHECK_NE(key_data->GetKeyType(), kKeyTypeSecret);
278
279

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

714
  CHECK(args[offset]->IsUint32());
321
  RSAKeyVariant variant =
322
1071
      static_cast<RSAKeyVariant>(args[offset].As<Uint32>()->Value());
323
324
357
  switch (variant) {
325
357
    case kKeyVariantRSA_OAEP: {
326

1071
      CHECK(args[offset + 1]->IsString());  // digest
327
714
      Utf8Value digest(env->isolate(), args[offset + 1]);
328
329
357
      params->digest = EVP_get_digestbyname(*digest);
330
357
      if (params->digest == nullptr) {
331
        THROW_ERR_CRYPTO_INVALID_DIGEST(env);
332
        return Nothing<bool>();
333
      }
334
335

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

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

1227
      SetEncodedValue(env, target, env->jwk_e_string(), e).IsNothing()) {
411
    return Nothing<bool>();
412
  }
413
414
409
  if (key->GetKeyType() == kKeyTypePrivate) {
415
211
    RSA_get0_factors(rsa, &p, &q);
416
211
    RSA_get0_crt_params(rsa, &dp, &dq, &qi);
417
211
    if (SetEncodedValue(env, target, env->jwk_d_string(), d).IsNothing() ||
418
422
        SetEncodedValue(env, target, env->jwk_p_string(), p).IsNothing() ||
419
422
        SetEncodedValue(env, target, env->jwk_q_string(), q).IsNothing() ||
420
422
        SetEncodedValue(env, target, env->jwk_dp_string(), dp).IsNothing() ||
421

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

633
        SetEncodedValue(env, target, env->jwk_qi_string(), qi).IsNothing()) {
423
      return Nothing<bool>();
424
    }
425
  }
426
427
409
  return Just(true);
428
}
429
430
502
std::shared_ptr<KeyObjectData> ImportJWKRsaKey(
431
    Environment* env,
432
    Local<Object> jwk,
433
    const FunctionCallbackInfo<Value>& args,
434
    unsigned int offset) {
435
  Local<Value> n_value;
436
  Local<Value> e_value;
437
  Local<Value> d_value;
438
439
1004
  if (!jwk->Get(env->context(), env->jwk_n_string()).ToLocal(&n_value) ||
440
1506
      !jwk->Get(env->context(), env->jwk_e_string()).ToLocal(&e_value) ||
441
1506
      !jwk->Get(env->context(), env->jwk_d_string()).ToLocal(&d_value) ||
442

2008
      !n_value->IsString() ||
443
1004
      !e_value->IsString()) {
444
    THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
445
    return std::shared_ptr<KeyObjectData>();
446
  }
447
448

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

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

960
        !jwk->Get(env->context(), env->jwk_qi_string()).ToLocal(&qi_value)) {
481
      THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
482
      return std::shared_ptr<KeyObjectData>();
483
    }
484
485
240
    if (!p_value->IsString() ||
486
480
        !q_value->IsString() ||
487
480
        !dp_value->IsString() ||
488

960
        !dq_value->IsString() ||
489
480
        !qi_value->IsString()) {
490
      THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
491
      return std::shared_ptr<KeyObjectData>();
492
    }
493
494
240
    ByteSource d = ByteSource::FromEncodedString(env, d_value.As<String>());
495
240
    ByteSource q = ByteSource::FromEncodedString(env, q_value.As<String>());
496
240
    ByteSource p = ByteSource::FromEncodedString(env, p_value.As<String>());
497
240
    ByteSource dp = ByteSource::FromEncodedString(env, dp_value.As<String>());
498
240
    ByteSource dq = ByteSource::FromEncodedString(env, dq_value.As<String>());
499
240
    ByteSource qi = ByteSource::FromEncodedString(env, qi_value.As<String>());
500
501

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


960
        !RSA_set0_factors(rsa.get(), p.ToBN().release(), q.ToBN().release()) ||
503
720
        !RSA_set0_crt_params(
504
            rsa.get(),
505
480
            dp.ToBN().release(),
506
480
            dq.ToBN().release(),
507

480
            qi.ToBN().release())) {
508
      THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
509
      return std::shared_ptr<KeyObjectData>();
510
    }
511
  }
512
513
502
  EVPKeyPointer pkey(EVP_PKEY_new());
514
502
  CHECK_EQ(EVP_PKEY_set1_RSA(pkey.get(), rsa.get()), 1);
515
516
502
  return KeyObjectData::CreateAsymmetric(type, ManagedEVPPKey(std::move(pkey)));
517
}
518
519
1691
Maybe<bool> GetRsaKeyDetail(
520
    Environment* env,
521
    std::shared_ptr<KeyObjectData> key,
522
    Local<Object> target) {
523
  const BIGNUM* e;  // Public Exponent
524
  const BIGNUM* n;  // Modulus
525
526
3382
  ManagedEVPPKey m_pkey = key->GetAsymmetricKey();
527
3382
  Mutex::ScopedLock lock(*m_pkey.mutex());
528
1691
  int type = EVP_PKEY_id(m_pkey.get());
529

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