GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_rsa.cc Lines: 257 320 80.3 %
Date: 2022-06-12 04:16:28 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.get(), 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
714
  char* data = MallocOpenSSL<char>(out_len);
248
1428
  ByteSource buf = ByteSource::Allocated(data, out_len);
249
714
  unsigned char* ptr = reinterpret_cast<unsigned char*>(data);
250
251
714
  if (cipher(
252
          ctx.get(),
253
          ptr,
254
          &out_len,
255
          in.data<unsigned char>(),
256
714
          in.size()) <= 0) {
257
48
    return WebCryptoCipherStatus::FAILED;
258
  }
259
260
666
  buf.Resize(out_len);
261
262
666
  *out = std::move(buf);
263
666
  return WebCryptoCipherStatus::OK;
264
}
265
}  // namespace
266
267
347
Maybe<bool> RSAKeyExportTraits::AdditionalConfig(
268
    const FunctionCallbackInfo<Value>& args,
269
    unsigned int offset,
270
    RSAKeyExportConfig* params) {
271

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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