GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_rsa.cc Lines: 257 320 80.3 %
Date: 2022-05-08 04:15:02 Branches: 192 326 58.9 %

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

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

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

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

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

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

330
  CHECK(args[*offset]->IsUint32());  // Variant
135

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

330
  CHECK(args[*offset + 2]->IsUint32());  // Exponent
137
138
165
  params->params.variant =
139
495
      static_cast<RSAKeyVariant>(args[*offset].As<Uint32>()->Value());
140
141

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

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

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

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

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

9
      CHECK(args[*offset + 1]->IsString());
164
6
      Utf8Value digest(env->isolate(), args[*offset + 1]);
165
3
      params->params.mgf1_md = EVP_get_digestbyname(*digest);
166
3
      if (params->params.mgf1_md == nullptr) {
167
        THROW_ERR_CRYPTO_INVALID_DIGEST(env,
168
          "mgf1_md specifies an invalid digest");
169
        return Nothing<bool>();
170
      }
171
    }
172
173

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

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

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

2142
  if (params.digest != nullptr &&
220
1428
      (EVP_PKEY_CTX_set_rsa_oaep_md(ctx.get(), params.digest) <= 0 ||
221
714
       EVP_PKEY_CTX_set_rsa_mgf1_md(ctx.get(), params.digest) <= 0)) {
222
    return WebCryptoCipherStatus::FAILED;
223
  }
224
225
714
  size_t label_len = params.label.size();
226
714
  if (label_len > 0) {
227
458
    void* label = OPENSSL_memdup(params.label.get(), label_len);
228
458
    CHECK_NOT_NULL(label);
229
458
    if (EVP_PKEY_CTX_set0_rsa_oaep_label(
230
      ctx.get(),
231
      static_cast<unsigned char*>(label),
232
458
      label_len) <= 0) {
233
      OPENSSL_free(label);
234
      return WebCryptoCipherStatus::FAILED;
235
    }
236
  }
237
238
714
  size_t out_len = 0;
239
714
  if (cipher(
240
          ctx.get(),
241
          nullptr,
242
          &out_len,
243
          in.data<unsigned char>(),
244
714
          in.size()) <= 0) {
245
    return WebCryptoCipherStatus::FAILED;
246
  }
247
248
714
  char* data = MallocOpenSSL<char>(out_len);
249
1428
  ByteSource buf = ByteSource::Allocated(data, out_len);
250
714
  unsigned char* ptr = reinterpret_cast<unsigned char*>(data);
251
252
714
  if (cipher(
253
          ctx.get(),
254
          ptr,
255
          &out_len,
256
          in.data<unsigned char>(),
257
714
          in.size()) <= 0) {
258
48
    return WebCryptoCipherStatus::FAILED;
259
  }
260
261
666
  buf.Resize(out_len);
262
263
666
  *out = std::move(buf);
264
666
  return WebCryptoCipherStatus::OK;
265
}
266
}  // namespace
267
268
347
Maybe<bool> RSAKeyExportTraits::AdditionalConfig(
269
    const FunctionCallbackInfo<Value>& args,
270
    unsigned int offset,
271
    RSAKeyExportConfig* params) {
272

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

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

714
  CHECK(args[offset]->IsUint32());
327
  RSAKeyVariant variant =
328
1071
      static_cast<RSAKeyVariant>(args[offset].As<Uint32>()->Value());
329
330
357
  switch (variant) {
331
357
    case kKeyVariantRSA_OAEP: {
332

1071
      CHECK(args[offset + 1]->IsString());  // digest
333
714
      Utf8Value digest(env->isolate(), args[offset + 1]);
334
335
357
      params->digest = EVP_get_digestbyname(*digest);
336
357
      if (params->digest == nullptr) {
337
        THROW_ERR_CRYPTO_INVALID_DIGEST(env);
338
        return Nothing<bool>();
339
      }
340
341

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

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

1233
      SetEncodedValue(env, target, env->jwk_e_string(), e).IsNothing()) {
417
    return Nothing<bool>();
418
  }
419
420
411
  if (key->GetKeyType() == kKeyTypePrivate) {
421
212
    RSA_get0_factors(rsa, &p, &q);
422
212
    RSA_get0_crt_params(rsa, &dp, &dq, &qi);
423
212
    if (SetEncodedValue(env, target, env->jwk_d_string(), d).IsNothing() ||
424
424
        SetEncodedValue(env, target, env->jwk_p_string(), p).IsNothing() ||
425
424
        SetEncodedValue(env, target, env->jwk_q_string(), q).IsNothing() ||
426
424
        SetEncodedValue(env, target, env->jwk_dp_string(), dp).IsNothing() ||
427

848
        SetEncodedValue(env, target, env->jwk_dq_string(), dq).IsNothing() ||
428

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

2008
      !n_value->IsString() ||
449
1004
      !e_value->IsString()) {
450
    THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
451
    return std::shared_ptr<KeyObjectData>();
452
  }
453
454

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

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

960
        !jwk->Get(env->context(), env->jwk_qi_string()).ToLocal(&qi_value)) {
487
      THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
488
      return std::shared_ptr<KeyObjectData>();
489
    }
490
491
240
    if (!p_value->IsString() ||
492
480
        !q_value->IsString() ||
493
480
        !dp_value->IsString() ||
494

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

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


960
        !RSA_set0_factors(rsa.get(), p.ToBN().release(), q.ToBN().release()) ||
509
720
        !RSA_set0_crt_params(
510
            rsa.get(),
511
480
            dp.ToBN().release(),
512
480
            dq.ToBN().release(),
513

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

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