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