• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
Setup(RsaKeyPairGenConfig * params)32 EVPKeyCtxPointer RsaKeyGenTraits::Setup(RsaKeyPairGenConfig* params) {
33   EVPKeyCtxPointer ctx(
34       EVP_PKEY_CTX_new_id(
35           params->params.variant == kKeyVariantRSA_PSS
36               ? EVP_PKEY_RSA_PSS
37               : EVP_PKEY_RSA,
38           nullptr));
39 
40   if (EVP_PKEY_keygen_init(ctx.get()) <= 0)
41     return EVPKeyCtxPointer();
42 
43   if (EVP_PKEY_CTX_set_rsa_keygen_bits(
44           ctx.get(),
45           params->params.modulus_bits) <= 0) {
46     return EVPKeyCtxPointer();
47   }
48 
49   // 0x10001 is the default RSA exponent.
50   if (params->params.exponent != 0x10001) {
51     BignumPointer bn(BN_new());
52     CHECK_NOT_NULL(bn.get());
53     CHECK(BN_set_word(bn.get(), params->params.exponent));
54     // EVP_CTX accepts ownership of bn on success.
55     if (EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx.get(), bn.get()) <= 0)
56       return EVPKeyCtxPointer();
57 
58     bn.release();
59   }
60 
61   if (params->params.variant == kKeyVariantRSA_PSS) {
62     if (params->params.md != nullptr &&
63         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     const EVP_MD* mgf1_md = params->params.mgf1_md;
72     if (mgf1_md == nullptr && params->params.md != nullptr) {
73       mgf1_md = params->params.md;
74     }
75 
76     if (mgf1_md != nullptr &&
77         EVP_PKEY_CTX_set_rsa_pss_keygen_mgf1_md(
78             ctx.get(),
79             mgf1_md) <= 0) {
80       return EVPKeyCtxPointer();
81     }
82 
83     int saltlen = params->params.saltlen;
84     if (saltlen < 0 && params->params.md != nullptr) {
85       saltlen = EVP_MD_size(params->params.md);
86     }
87 
88     if (saltlen >= 0 &&
89         EVP_PKEY_CTX_set_rsa_pss_keygen_saltlen(
90             ctx.get(),
91             saltlen) <= 0) {
92       return EVPKeyCtxPointer();
93     }
94   }
95 
96   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
AdditionalConfig(CryptoJobMode mode,const FunctionCallbackInfo<Value> & args,unsigned int * offset,RsaKeyPairGenConfig * params)126 Maybe<bool> RsaKeyGenTraits::AdditionalConfig(
127     CryptoJobMode mode,
128     const FunctionCallbackInfo<Value>& args,
129     unsigned int* offset,
130     RsaKeyPairGenConfig* params) {
131   Environment* env = Environment::GetCurrent(args);
132 
133   CHECK(args[*offset]->IsUint32());  // Variant
134   CHECK(args[*offset + 1]->IsUint32());  // Modulus bits
135   CHECK(args[*offset + 2]->IsUint32());  // Exponent
136 
137   params->params.variant =
138       static_cast<RSAKeyVariant>(args[*offset].As<Uint32>()->Value());
139 
140   CHECK_IMPLIES(params->params.variant != kKeyVariantRSA_PSS,
141                 args.Length() == 10);
142   CHECK_IMPLIES(params->params.variant == kKeyVariantRSA_PSS,
143                 args.Length() == 13);
144 
145   params->params.modulus_bits = args[*offset + 1].As<Uint32>()->Value();
146   params->params.exponent = args[*offset + 2].As<Uint32>()->Value();
147 
148   *offset += 3;
149 
150   if (params->params.variant == kKeyVariantRSA_PSS) {
151     if (!args[*offset]->IsUndefined()) {
152       CHECK(args[*offset]->IsString());
153       Utf8Value digest(env->isolate(), args[*offset]);
154       params->params.md = EVP_get_digestbyname(*digest);
155       if (params->params.md == nullptr) {
156         THROW_ERR_CRYPTO_INVALID_DIGEST(env, "Invalid digest: %s", *digest);
157         return Nothing<bool>();
158       }
159     }
160 
161     if (!args[*offset + 1]->IsUndefined()) {
162       CHECK(args[*offset + 1]->IsString());
163       Utf8Value digest(env->isolate(), args[*offset + 1]);
164       params->params.mgf1_md = EVP_get_digestbyname(*digest);
165       if (params->params.mgf1_md == nullptr) {
166         THROW_ERR_CRYPTO_INVALID_DIGEST(
167             env, "Invalid MGF1 digest: %s", *digest);
168         return Nothing<bool>();
169       }
170     }
171 
172     if (!args[*offset + 2]->IsUndefined()) {
173       CHECK(args[*offset + 2]->IsInt32());
174       params->params.saltlen = args[*offset + 2].As<Int32>()->Value();
175       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     *offset += 3;
184   }
185 
186   return Just(true);
187 }
188 
189 namespace {
RSA_JWK_Export(KeyObjectData * key_data,const RSAKeyExportConfig & params,ByteSource * out)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>
RSA_Cipher(Environment * env,KeyObjectData * key_data,const RSACipherConfig & params,const ByteSource & in,ByteSource * out)199 WebCryptoCipherStatus RSA_Cipher(
200     Environment* env,
201     KeyObjectData* key_data,
202     const RSACipherConfig& params,
203     const ByteSource& in,
204     ByteSource* out) {
205   CHECK_NE(key_data->GetKeyType(), kKeyTypeSecret);
206   ManagedEVPPKey m_pkey = key_data->GetAsymmetricKey();
207   Mutex::ScopedLock lock(*m_pkey.mutex());
208 
209   EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(m_pkey.get(), nullptr));
210 
211   if (!ctx || init(ctx.get()) <= 0)
212     return WebCryptoCipherStatus::FAILED;
213 
214   if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), params.padding) <= 0) {
215     return WebCryptoCipherStatus::FAILED;
216   }
217 
218   if (params.digest != nullptr &&
219       (EVP_PKEY_CTX_set_rsa_oaep_md(ctx.get(), params.digest) <= 0 ||
220        EVP_PKEY_CTX_set_rsa_mgf1_md(ctx.get(), params.digest) <= 0)) {
221     return WebCryptoCipherStatus::FAILED;
222   }
223 
224   if (!SetRsaOaepLabel(ctx, params.label)) return WebCryptoCipherStatus::FAILED;
225 
226   size_t out_len = 0;
227   if (cipher(
228           ctx.get(),
229           nullptr,
230           &out_len,
231           in.data<unsigned char>(),
232           in.size()) <= 0) {
233     return WebCryptoCipherStatus::FAILED;
234   }
235 
236   ByteSource::Builder buf(out_len);
237 
238   if (cipher(ctx.get(),
239              buf.data<unsigned char>(),
240              &out_len,
241              in.data<unsigned char>(),
242              in.size()) <= 0) {
243     return WebCryptoCipherStatus::FAILED;
244   }
245 
246   *out = std::move(buf).release(out_len);
247   return WebCryptoCipherStatus::OK;
248 }
249 }  // namespace
250 
AdditionalConfig(const FunctionCallbackInfo<Value> & args,unsigned int offset,RSAKeyExportConfig * params)251 Maybe<bool> RSAKeyExportTraits::AdditionalConfig(
252     const FunctionCallbackInfo<Value>& args,
253     unsigned int offset,
254     RSAKeyExportConfig* params) {
255   CHECK(args[offset]->IsUint32());  // RSAKeyVariant
256   params->variant =
257       static_cast<RSAKeyVariant>(args[offset].As<Uint32>()->Value());
258   return Just(true);
259 }
260 
DoExport(std::shared_ptr<KeyObjectData> key_data,WebCryptoKeyFormat format,const RSAKeyExportConfig & params,ByteSource * out)261 WebCryptoKeyExportStatus RSAKeyExportTraits::DoExport(
262     std::shared_ptr<KeyObjectData> key_data,
263     WebCryptoKeyFormat format,
264     const RSAKeyExportConfig& params,
265     ByteSource* out) {
266   CHECK_NE(key_data->GetKeyType(), kKeyTypeSecret);
267 
268   switch (format) {
269     case kWebCryptoKeyFormatRaw:
270       // Not supported for RSA keys of either type
271       return WebCryptoKeyExportStatus::FAILED;
272     case kWebCryptoKeyFormatJWK:
273       return RSA_JWK_Export(key_data.get(), params, out);
274     case kWebCryptoKeyFormatPKCS8:
275       if (key_data->GetKeyType() != kKeyTypePrivate)
276         return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
277       return PKEY_PKCS8_Export(key_data.get(), out);
278     case kWebCryptoKeyFormatSPKI:
279       if (key_data->GetKeyType() != kKeyTypePublic)
280         return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
281       return PKEY_SPKI_Export(key_data.get(), out);
282     default:
283       UNREACHABLE();
284   }
285 }
286 
RSACipherConfig(RSACipherConfig && other)287 RSACipherConfig::RSACipherConfig(RSACipherConfig&& other) noexcept
288     : mode(other.mode),
289       label(std::move(other.label)),
290       padding(other.padding),
291       digest(other.digest) {}
292 
MemoryInfo(MemoryTracker * tracker) const293 void RSACipherConfig::MemoryInfo(MemoryTracker* tracker) const {
294   if (mode == kCryptoJobAsync)
295     tracker->TrackFieldWithSize("label", label.size());
296 }
297 
AdditionalConfig(CryptoJobMode mode,const FunctionCallbackInfo<Value> & args,unsigned int offset,WebCryptoCipherMode cipher_mode,RSACipherConfig * params)298 Maybe<bool> RSACipherTraits::AdditionalConfig(
299     CryptoJobMode mode,
300     const FunctionCallbackInfo<Value>& args,
301     unsigned int offset,
302     WebCryptoCipherMode cipher_mode,
303     RSACipherConfig* params) {
304   Environment* env = Environment::GetCurrent(args);
305 
306   params->mode = mode;
307   params->padding = RSA_PKCS1_OAEP_PADDING;
308 
309   CHECK(args[offset]->IsUint32());
310   RSAKeyVariant variant =
311       static_cast<RSAKeyVariant>(args[offset].As<Uint32>()->Value());
312 
313   switch (variant) {
314     case kKeyVariantRSA_OAEP: {
315       CHECK(args[offset + 1]->IsString());  // digest
316       Utf8Value digest(env->isolate(), args[offset + 1]);
317 
318       params->digest = EVP_get_digestbyname(*digest);
319       if (params->digest == nullptr) {
320         THROW_ERR_CRYPTO_INVALID_DIGEST(env, "Invalid digest: %s", *digest);
321         return Nothing<bool>();
322       }
323 
324       if (IsAnyByteSource(args[offset + 2])) {
325         ArrayBufferOrViewContents<char> label(args[offset + 2]);
326         if (UNLIKELY(!label.CheckSizeInt32())) {
327           THROW_ERR_OUT_OF_RANGE(env, "label is too big");
328           return Nothing<bool>();
329         }
330         params->label = label.ToCopy();
331       }
332       break;
333     }
334     default:
335       THROW_ERR_CRYPTO_INVALID_KEYTYPE(env);
336       return Nothing<bool>();
337   }
338 
339   return Just(true);
340 }
341 
DoCipher(Environment * env,std::shared_ptr<KeyObjectData> key_data,WebCryptoCipherMode cipher_mode,const RSACipherConfig & params,const ByteSource & in,ByteSource * out)342 WebCryptoCipherStatus RSACipherTraits::DoCipher(
343     Environment* env,
344     std::shared_ptr<KeyObjectData> key_data,
345     WebCryptoCipherMode cipher_mode,
346     const RSACipherConfig& params,
347     const ByteSource& in,
348     ByteSource* out) {
349   switch (cipher_mode) {
350     case kWebCryptoCipherEncrypt:
351       CHECK_EQ(key_data->GetKeyType(), kKeyTypePublic);
352       return RSA_Cipher<EVP_PKEY_encrypt_init, EVP_PKEY_encrypt>(
353           env, key_data.get(), params, in, out);
354     case kWebCryptoCipherDecrypt:
355       CHECK_EQ(key_data->GetKeyType(), kKeyTypePrivate);
356       return RSA_Cipher<EVP_PKEY_decrypt_init, EVP_PKEY_decrypt>(
357           env, key_data.get(), params, in, out);
358   }
359   return WebCryptoCipherStatus::FAILED;
360 }
361 
ExportJWKRsaKey(Environment * env,std::shared_ptr<KeyObjectData> key,Local<Object> target)362 Maybe<bool> ExportJWKRsaKey(
363     Environment* env,
364     std::shared_ptr<KeyObjectData> key,
365     Local<Object> target) {
366   ManagedEVPPKey m_pkey = key->GetAsymmetricKey();
367   Mutex::ScopedLock lock(*m_pkey.mutex());
368   int type = EVP_PKEY_id(m_pkey.get());
369   CHECK(type == EVP_PKEY_RSA || type == EVP_PKEY_RSA_PSS);
370 
371   // TODO(tniessen): Remove the "else" branch once we drop support for OpenSSL
372   // versions older than 1.1.1e via FIPS / dynamic linking.
373   const RSA* rsa;
374   if (OpenSSL_version_num() >= 0x1010105fL) {
375     rsa = EVP_PKEY_get0_RSA(m_pkey.get());
376   } else {
377     rsa = static_cast<const RSA*>(EVP_PKEY_get0(m_pkey.get()));
378   }
379   CHECK_NOT_NULL(rsa);
380 
381   const BIGNUM* n;
382   const BIGNUM* e;
383   const BIGNUM* d;
384   const BIGNUM* p;
385   const BIGNUM* q;
386   const BIGNUM* dp;
387   const BIGNUM* dq;
388   const BIGNUM* qi;
389   RSA_get0_key(rsa, &n, &e, &d);
390 
391   if (target->Set(
392           env->context(),
393           env->jwk_kty_string(),
394           env->jwk_rsa_string()).IsNothing()) {
395     return Nothing<bool>();
396   }
397 
398   if (SetEncodedValue(env, target, env->jwk_n_string(), n).IsNothing() ||
399       SetEncodedValue(env, target, env->jwk_e_string(), e).IsNothing()) {
400     return Nothing<bool>();
401   }
402 
403   if (key->GetKeyType() == kKeyTypePrivate) {
404     RSA_get0_factors(rsa, &p, &q);
405     RSA_get0_crt_params(rsa, &dp, &dq, &qi);
406     if (SetEncodedValue(env, target, env->jwk_d_string(), d).IsNothing() ||
407         SetEncodedValue(env, target, env->jwk_p_string(), p).IsNothing() ||
408         SetEncodedValue(env, target, env->jwk_q_string(), q).IsNothing() ||
409         SetEncodedValue(env, target, env->jwk_dp_string(), dp).IsNothing() ||
410         SetEncodedValue(env, target, env->jwk_dq_string(), dq).IsNothing() ||
411         SetEncodedValue(env, target, env->jwk_qi_string(), qi).IsNothing()) {
412       return Nothing<bool>();
413     }
414   }
415 
416   return Just(true);
417 }
418 
ImportJWKRsaKey(Environment * env,Local<Object> jwk,const FunctionCallbackInfo<Value> & args,unsigned int offset)419 std::shared_ptr<KeyObjectData> ImportJWKRsaKey(
420     Environment* env,
421     Local<Object> jwk,
422     const FunctionCallbackInfo<Value>& args,
423     unsigned int offset) {
424   Local<Value> n_value;
425   Local<Value> e_value;
426   Local<Value> d_value;
427 
428   if (!jwk->Get(env->context(), env->jwk_n_string()).ToLocal(&n_value) ||
429       !jwk->Get(env->context(), env->jwk_e_string()).ToLocal(&e_value) ||
430       !jwk->Get(env->context(), env->jwk_d_string()).ToLocal(&d_value) ||
431       !n_value->IsString() ||
432       !e_value->IsString()) {
433     THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
434     return std::shared_ptr<KeyObjectData>();
435   }
436 
437   if (!d_value->IsUndefined() && !d_value->IsString()) {
438     THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
439     return std::shared_ptr<KeyObjectData>();
440   }
441 
442   KeyType type = d_value->IsString() ? kKeyTypePrivate : kKeyTypePublic;
443 
444   RsaPointer rsa(RSA_new());
445 
446   ByteSource n = ByteSource::FromEncodedString(env, n_value.As<String>());
447   ByteSource e = ByteSource::FromEncodedString(env, e_value.As<String>());
448 
449   if (!RSA_set0_key(
450           rsa.get(),
451           n.ToBN().release(),
452           e.ToBN().release(),
453           nullptr)) {
454     THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
455     return std::shared_ptr<KeyObjectData>();
456   }
457 
458   if (type == kKeyTypePrivate) {
459     Local<Value> p_value;
460     Local<Value> q_value;
461     Local<Value> dp_value;
462     Local<Value> dq_value;
463     Local<Value> qi_value;
464 
465     if (!jwk->Get(env->context(), env->jwk_p_string()).ToLocal(&p_value) ||
466         !jwk->Get(env->context(), env->jwk_q_string()).ToLocal(&q_value) ||
467         !jwk->Get(env->context(), env->jwk_dp_string()).ToLocal(&dp_value) ||
468         !jwk->Get(env->context(), env->jwk_dq_string()).ToLocal(&dq_value) ||
469         !jwk->Get(env->context(), env->jwk_qi_string()).ToLocal(&qi_value)) {
470       THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
471       return std::shared_ptr<KeyObjectData>();
472     }
473 
474     if (!p_value->IsString() ||
475         !q_value->IsString() ||
476         !dp_value->IsString() ||
477         !dq_value->IsString() ||
478         !qi_value->IsString()) {
479       THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
480       return std::shared_ptr<KeyObjectData>();
481     }
482 
483     ByteSource d = ByteSource::FromEncodedString(env, d_value.As<String>());
484     ByteSource q = ByteSource::FromEncodedString(env, q_value.As<String>());
485     ByteSource p = ByteSource::FromEncodedString(env, p_value.As<String>());
486     ByteSource dp = ByteSource::FromEncodedString(env, dp_value.As<String>());
487     ByteSource dq = ByteSource::FromEncodedString(env, dq_value.As<String>());
488     ByteSource qi = ByteSource::FromEncodedString(env, qi_value.As<String>());
489 
490     if (!RSA_set0_key(rsa.get(), nullptr, nullptr, d.ToBN().release()) ||
491         !RSA_set0_factors(rsa.get(), p.ToBN().release(), q.ToBN().release()) ||
492         !RSA_set0_crt_params(
493             rsa.get(),
494             dp.ToBN().release(),
495             dq.ToBN().release(),
496             qi.ToBN().release())) {
497       THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK RSA key");
498       return std::shared_ptr<KeyObjectData>();
499     }
500   }
501 
502   EVPKeyPointer pkey(EVP_PKEY_new());
503   CHECK_EQ(EVP_PKEY_set1_RSA(pkey.get(), rsa.get()), 1);
504 
505   return KeyObjectData::CreateAsymmetric(type, ManagedEVPPKey(std::move(pkey)));
506 }
507 
GetRsaKeyDetail(Environment * env,std::shared_ptr<KeyObjectData> key,Local<Object> target)508 Maybe<bool> GetRsaKeyDetail(
509     Environment* env,
510     std::shared_ptr<KeyObjectData> key,
511     Local<Object> target) {
512   const BIGNUM* e;  // Public Exponent
513   const BIGNUM* n;  // Modulus
514 
515   ManagedEVPPKey m_pkey = key->GetAsymmetricKey();
516   Mutex::ScopedLock lock(*m_pkey.mutex());
517   int type = EVP_PKEY_id(m_pkey.get());
518   CHECK(type == EVP_PKEY_RSA || type == EVP_PKEY_RSA_PSS);
519 
520   // TODO(tniessen): Remove the "else" branch once we drop support for OpenSSL
521   // versions older than 1.1.1e via FIPS / dynamic linking.
522   const RSA* rsa;
523   if (OpenSSL_version_num() >= 0x1010105fL) {
524     rsa = EVP_PKEY_get0_RSA(m_pkey.get());
525   } else {
526     rsa = static_cast<const RSA*>(EVP_PKEY_get0(m_pkey.get()));
527   }
528   CHECK_NOT_NULL(rsa);
529 
530   RSA_get0_key(rsa, &n, &e, nullptr);
531 
532   size_t modulus_length = BN_num_bits(n);
533 
534   if (target
535           ->Set(
536               env->context(),
537               env->modulus_length_string(),
538               Number::New(env->isolate(), static_cast<double>(modulus_length)))
539           .IsNothing()) {
540     return Nothing<bool>();
541   }
542 
543   std::unique_ptr<BackingStore> public_exponent;
544   {
545     NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
546     public_exponent =
547         ArrayBuffer::NewBackingStore(env->isolate(), BN_num_bytes(e));
548   }
549   CHECK_EQ(BN_bn2binpad(e,
550                         static_cast<unsigned char*>(public_exponent->Data()),
551                         public_exponent->ByteLength()),
552            static_cast<int>(public_exponent->ByteLength()));
553 
554   if (target
555           ->Set(env->context(),
556                 env->public_exponent_string(),
557                 ArrayBuffer::New(env->isolate(), std::move(public_exponent)))
558           .IsNothing()) {
559     return Nothing<bool>();
560   }
561 
562   if (type == EVP_PKEY_RSA_PSS) {
563     // Due to the way ASN.1 encoding works, default values are omitted when
564     // encoding the data structure. However, there are also RSA-PSS keys for
565     // which no parameters are set. In that case, the ASN.1 RSASSA-PSS-params
566     // sequence will be missing entirely and RSA_get0_pss_params will return
567     // nullptr. If parameters are present but all parameters are set to their
568     // default values, an empty sequence will be stored in the ASN.1 structure.
569     // In that case, RSA_get0_pss_params does not return nullptr but all fields
570     // of the returned RSA_PSS_PARAMS will be set to nullptr.
571 
572     const RSA_PSS_PARAMS* params = RSA_get0_pss_params(rsa);
573     if (params != nullptr) {
574       int hash_nid = NID_sha1;
575       int mgf_nid = NID_mgf1;
576       int mgf1_hash_nid = NID_sha1;
577       int64_t salt_length = 20;
578 
579       if (params->hashAlgorithm != nullptr) {
580         hash_nid = OBJ_obj2nid(params->hashAlgorithm->algorithm);
581       }
582 
583       if (target
584               ->Set(
585                   env->context(),
586                   env->hash_algorithm_string(),
587                   OneByteString(env->isolate(), OBJ_nid2ln(hash_nid)))
588               .IsNothing()) {
589         return Nothing<bool>();
590       }
591 
592       if (params->maskGenAlgorithm != nullptr) {
593         mgf_nid = OBJ_obj2nid(params->maskGenAlgorithm->algorithm);
594         if (mgf_nid == NID_mgf1) {
595           mgf1_hash_nid = OBJ_obj2nid(params->maskHash->algorithm);
596         }
597       }
598 
599       // If, for some reason, the MGF is not MGF1, then the MGF1 hash function
600       // is intentionally not added to the object.
601       if (mgf_nid == NID_mgf1) {
602         if (target
603                 ->Set(
604                     env->context(),
605                     env->mgf1_hash_algorithm_string(),
606                     OneByteString(env->isolate(), OBJ_nid2ln(mgf1_hash_nid)))
607                 .IsNothing()) {
608           return Nothing<bool>();
609         }
610       }
611 
612       if (params->saltLength != nullptr) {
613         if (ASN1_INTEGER_get_int64(&salt_length, params->saltLength) != 1) {
614           ThrowCryptoError(env, ERR_get_error(), "ASN1_INTEGER_get_in64 error");
615           return Nothing<bool>();
616         }
617       }
618 
619       if (target
620               ->Set(
621                   env->context(),
622                   env->salt_length_string(),
623                   Number::New(env->isolate(), static_cast<double>(salt_length)))
624               .IsNothing()) {
625         return Nothing<bool>();
626       }
627     }
628   }
629 
630   return Just<bool>(true);
631 }
632 
633 namespace RSAAlg {
Initialize(Environment * env,Local<Object> target)634 void Initialize(Environment* env, Local<Object> target) {
635   RSAKeyPairGenJob::Initialize(env, target);
636   RSAKeyExportJob::Initialize(env, target);
637   RSACipherJob::Initialize(env, target);
638 
639   NODE_DEFINE_CONSTANT(target, kKeyVariantRSA_SSA_PKCS1_v1_5);
640   NODE_DEFINE_CONSTANT(target, kKeyVariantRSA_PSS);
641   NODE_DEFINE_CONSTANT(target, kKeyVariantRSA_OAEP);
642 }
643 
RegisterExternalReferences(ExternalReferenceRegistry * registry)644 void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
645   RSAKeyPairGenJob::RegisterExternalReferences(registry);
646   RSAKeyExportJob::RegisterExternalReferences(registry);
647   RSACipherJob::RegisterExternalReferences(registry);
648 }
649 }  // namespace RSAAlg
650 }  // namespace crypto
651 }  // namespace node
652