GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_rsa.cc Lines: 252 315 80.0 %
Date: 2021-09-22 04:12:37 Branches: 207 354 58.5 %

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::FunctionCallbackInfo;
19
using v8::Int32;
20
using v8::Just;
21
using v8::Local;
22
using v8::Maybe;
23
using v8::Nothing;
24
using v8::Number;
25
using v8::Object;
26
using v8::String;
27
using v8::Uint32;
28
using v8::Value;
29
30
namespace crypto {
31
162
EVPKeyCtxPointer RsaKeyGenTraits::Setup(RsaKeyPairGenConfig* params) {
32
  EVPKeyCtxPointer ctx(
33
      EVP_PKEY_CTX_new_id(
34
162
          params->params.variant == kKeyVariantRSA_PSS
35
              ? EVP_PKEY_RSA_PSS
36
              : EVP_PKEY_RSA,
37
324
          nullptr));
38
39
162
  if (EVP_PKEY_keygen_init(ctx.get()) <= 0)
40
    return EVPKeyCtxPointer();
41
42
162
  if (EVP_PKEY_CTX_set_rsa_keygen_bits(
43
          ctx.get(),
44
162
          params->params.modulus_bits) <= 0) {
45
    return EVPKeyCtxPointer();
46
  }
47
48
  // 0x10001 is the default RSA exponent.
49
162
  if (params->params.exponent != 0x10001) {
50
2
    BignumPointer bn(BN_new());
51
2
    CHECK_NOT_NULL(bn.get());
52
2
    CHECK(BN_set_word(bn.get(), params->params.exponent));
53
    // EVP_CTX accepts ownership of bn on success.
54
2
    if (EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx.get(), bn.get()) <= 0)
55
      return EVPKeyCtxPointer();
56
57
2
    bn.release();
58
  }
59
60
162
  if (params->params.variant == kKeyVariantRSA_PSS) {
61

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

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

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

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

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

326
  CHECK(args[*offset]->IsUint32());  // Variant
133

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

326
  CHECK(args[*offset + 2]->IsUint32());  // Exponent
135
136
163
  params->params.variant =
137
489
      static_cast<RSAKeyVariant>(args[*offset].As<Uint32>()->Value());
138
139

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

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

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

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

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

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

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

10
      CHECK(args[*offset + 2]->IsInt32());
173
15
      params->params.saltlen = args[*offset + 2].As<Int32>()->Value();
174
5
      if (params->params.saltlen < 0) {
175
        THROW_ERR_OUT_OF_RANGE(
176
          env,
177
          "salt length is out of range");
178
        return Nothing<bool>();
179
      }
180
    }
181
182
7
    *offset += 3;
183
  }
184
185
163
  return Just(true);
186
}
187
188
namespace {
189
WebCryptoKeyExportStatus RSA_JWK_Export(
190
    KeyObjectData* key_data,
191
    const RSAKeyExportConfig& params,
192
    ByteSource* out) {
193
  return WebCryptoKeyExportStatus::FAILED;
194
}
195
196
template <PublicKeyCipher::EVP_PKEY_cipher_init_t init,
197
          PublicKeyCipher::EVP_PKEY_cipher_t cipher>
198
714
WebCryptoCipherStatus RSA_Cipher(
199
    Environment* env,
200
    KeyObjectData* key_data,
201
    const RSACipherConfig& params,
202
    const ByteSource& in,
203
    ByteSource* out) {
204

357
  CHECK_NE(key_data->GetKeyType(), kKeyTypeSecret);
205
714
  ManagedEVPPKey m_pkey = key_data->GetAsymmetricKey();
206
714
  Mutex::ScopedLock lock(*m_pkey.mutex());
207
208
714
  EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(m_pkey.get(), nullptr));
209
210



357
  if (!ctx || init(ctx.get()) <= 0)
211
    return WebCryptoCipherStatus::FAILED;
212
213

357
  if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), params.padding) <= 0) {
214
    return WebCryptoCipherStatus::FAILED;
215
  }
216
217



1071
  if (params.digest != nullptr &&
218

714
      (EVP_PKEY_CTX_set_rsa_oaep_md(ctx.get(), params.digest) <= 0 ||
219
357
       EVP_PKEY_CTX_set_rsa_mgf1_md(ctx.get(), params.digest) <= 0)) {
220
    return WebCryptoCipherStatus::FAILED;
221
  }
222
223
357
  size_t label_len = params.label.size();
224

357
  if (label_len > 0) {
225
229
    void* label = OPENSSL_memdup(params.label.get(), label_len);
226

229
    CHECK_NOT_NULL(label);
227
229
    if (EVP_PKEY_CTX_set0_rsa_oaep_label(
228
      ctx.get(),
229
      static_cast<unsigned char*>(label),
230

229
      label_len) <= 0) {
231
      OPENSSL_free(label);
232
      return WebCryptoCipherStatus::FAILED;
233
    }
234
  }
235
236
357
  size_t out_len = 0;
237
357
  if (cipher(
238
          ctx.get(),
239
          nullptr,
240
          &out_len,
241
          in.data<unsigned char>(),
242

357
          in.size()) <= 0) {
243
    return WebCryptoCipherStatus::FAILED;
244
  }
245
246
357
  char* data = MallocOpenSSL<char>(out_len);
247
714
  ByteSource buf = ByteSource::Allocated(data, out_len);
248
357
  unsigned char* ptr = reinterpret_cast<unsigned char*>(data);
249
250
357
  if (cipher(
251
          ctx.get(),
252
          ptr,
253
          &out_len,
254
          in.data<unsigned char>(),
255

357
          in.size()) <= 0) {
256
24
    return WebCryptoCipherStatus::FAILED;
257
  }
258
259
333
  buf.Resize(out_len);
260
261
333
  *out = std::move(buf);
262
333
  return WebCryptoCipherStatus::OK;
263
}
264
}  // namespace
265
266
347
Maybe<bool> RSAKeyExportTraits::AdditionalConfig(
267
    const FunctionCallbackInfo<Value>& args,
268
    unsigned int offset,
269
    RSAKeyExportConfig* params) {
270

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

1701
  CHECK(type == EVP_PKEY_RSA || type == EVP_PKEY_RSA_PSS);
534
535
  // TODO(tniessen): Remove the "else" branch once we drop support for OpenSSL
536
  // versions older than 1.1.1e via FIPS / dynamic linking.
537
  const RSA* rsa;
538
1701
  if (OpenSSL_version_num() >= 0x1010105fL) {
539
1701
    rsa = EVP_PKEY_get0_RSA(m_pkey.get());
540
  } else {
541
    rsa = static_cast<const RSA*>(EVP_PKEY_get0(m_pkey.get()));
542
  }
543
1701
  CHECK_NOT_NULL(rsa);
544
545
1701
  RSA_get0_key(rsa, &n, &e, nullptr);
546
547
1701
  size_t modulus_length = BN_num_bytes(n) * CHAR_BIT;
548
549
1701
  if (target
550
1701
          ->Set(
551
              env->context(),
552
              env->modulus_length_string(),
553
5103
              Number::New(env->isolate(), static_cast<double>(modulus_length)))
554
1701
          .IsNothing()) {
555
    return Nothing<bool>();
556
  }
557
558
1701
  int len = BN_num_bytes(e);
559
3402
  AllocatedBuffer public_exponent = AllocatedBuffer::AllocateManaged(env, len);
560
  unsigned char* data =
561
1701
      reinterpret_cast<unsigned char*>(public_exponent.data());
562
1701
  CHECK_EQ(BN_bn2binpad(e, data, len), len);
563
564
1701
  if (target
565
1701
          ->Set(
566
              env->context(),
567
              env->public_exponent_string(),
568
5103
              public_exponent.ToArrayBuffer())
569
1701
          .IsNothing()) {
570
    return Nothing<bool>();
571
  }
572
573
1701
  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
30
    const RSA_PSS_PARAMS* params = RSA_get0_pss_params(rsa);
584
30
    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
1701
  return Just<bool>(true);
642
}
643
644
namespace RSAAlg {
645
4299
void Initialize(Environment* env, Local<Object> target) {
646
4299
  RSAKeyPairGenJob::Initialize(env, target);
647
4299
  RSAKeyExportJob::Initialize(env, target);
648
4299
  RSACipherJob::Initialize(env, target);
649
650
12897
  NODE_DEFINE_CONSTANT(target, kKeyVariantRSA_SSA_PKCS1_v1_5);
651
12897
  NODE_DEFINE_CONSTANT(target, kKeyVariantRSA_PSS);
652
8598
  NODE_DEFINE_CONSTANT(target, kKeyVariantRSA_OAEP);
653
4299
}
654
}  // namespace RSAAlg
655
}  // namespace crypto
656
}  // namespace node