crypto: fetch ciphers for private-key encoding · nodejs/node@764e0d1 · GitHub
Skip to content

Commit 764e0d1

Browse files
panvaaduh95
authored andcommitted
crypto: fetch ciphers for private-key encoding
Resolve provider ciphers before serializing private keys and retain the fetched implementation across encoding configuration copies and async key generation. Keep format-specific restrictions in the serializers. Signed-off-by: Filip Skokan <panva.ip@gmail.com> Assisted-by: Codex PR-URL: #66108 Backport-PR-URL: #66233 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
1 parent 50ffed1 commit 764e0d1

5 files changed

Lines changed: 168 additions & 11 deletions

File tree

‎deps/ncrypto/ncrypto.cc‎

Lines changed: 15 additions & 6 deletions

‎deps/ncrypto/ncrypto.h‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,7 @@ class Cipher final {
542542
unsigned char* iv) const;
543543

544544
static const Cipher FromName(const char* name, CipherCache* cache = nullptr);
545+
static const Cipher FromNameForKeyEncoding(const char* name);
545546
static const Cipher FromNid(int nid, CipherCache* cache = nullptr);
546547
static const Cipher FromCtx(const CipherCtxPointer& ctx);
547548

@@ -1250,7 +1251,7 @@ class EVPKeyPointer final {
12501251
using PublicKeyEncodingConfig = AsymmetricKeyEncodingConfig;
12511252

12521253
struct PrivateKeyEncodingConfig : public AsymmetricKeyEncodingConfig {
1253-
const EVP_CIPHER* cipher = nullptr;
1254+
Cipher cipher;
12541255
std::optional<DataPointer> passphrase = std::nullopt;
12551256
PrivateKeyEncodingConfig() = default;
12561257
PrivateKeyEncodingConfig(bool output_key_object,
@@ -2194,7 +2195,6 @@ class KDF final {
21942195
#endif
21952196

21962197
const EVP_MD* getDigestByName(const char* name);
2197-
const EVP_CIPHER* getCipherByName(const char* name);
21982198

21992199
// Verify that the specified HKDF output length is valid for the given digest.
22002200
// The maximum length for HKDF output for a given digest is 255 times the

‎src/crypto/crypto_keys.cc‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -539,8 +539,8 @@ KeyObjectData::GetPrivateKeyEncodingFromJs(
539539
if (context != kKeyContextInput) {
540540
if (args[*offset]->IsString()) {
541541
Utf8Value cipher_name(env->isolate(), args[*offset]);
542-
config.cipher = ncrypto::getCipherByName(*cipher_name);
543-
if (config.cipher == nullptr) {
542+
config.cipher = ncrypto::Cipher::FromNameForKeyEncoding(*cipher_name);
543+
if (!config.cipher) {
544544
THROW_ERR_CRYPTO_UNKNOWN_CIPHER(env);
545545
return Nothing<EVPKeyPointer::PrivateKeyEncodingConfig>();
546546
}
@@ -553,7 +553,7 @@ KeyObjectData::GetPrivateKeyEncodingFromJs(
553553
}
554554

555555
if (IsAnyBufferSource(args[*offset])) {
556-
CHECK_IMPLIES(context != kKeyContextInput, config.cipher != nullptr);
556+
CHECK_IMPLIES(context != kKeyContextInput, config.cipher);
557557
ArrayBufferOrViewContents<char> passphrase(args[*offset]);
558558
if (!passphrase.CheckSizeInt32()) [[unlikely]] {
559559
THROW_ERR_OUT_OF_RANGE(env, "passphrase is too big");

‎test/cctest/test_node_crypto.cc‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,3 +673,38 @@ TEST(NodeCrypto, UnavailableBoringSSLKeyAlgorithms) {
673673
}
674674
}
675675
#endif
676+
677+
#if NCRYPTO_USE_OPENSSL3_PROVIDER
678+
TEST(NodeCrypto, PrivateKeyEncodingOwnsFetchedCipher) {
679+
ncrypto::ClearErrorOnReturn clear_errors;
680+
EVPKeyPointer::PrivateKeyEncodingConfig assigned;
681+
{
682+
EVPKeyPointer::PrivateKeyEncodingConfig original;
683+
original.cipher =
684+
ncrypto::Cipher::FromNameForKeyEncoding("2.16.840.1.101.3.4.1.42");
685+
ASSERT_TRUE(original.cipher);
686+
ASSERT_NE(EVP_CIPHER_get0_provider(original.cipher.get()), nullptr);
687+
const auto copied = original;
688+
assigned = copied;
689+
}
690+
691+
ASSERT_TRUE(assigned.cipher);
692+
EXPECT_NE(EVP_CIPHER_get0_provider(assigned.cipher.get()), nullptr);
693+
EXPECT_EQ(EVP_CIPHER_is_a(assigned.cipher.get(), "AES-256-CBC"), 1);
694+
auto ctx = ncrypto::CipherCtxPointer::New();
695+
const unsigned char key[32] = {};
696+
const unsigned char iv[16] = {};
697+
EXPECT_TRUE(ctx.init(assigned.cipher, true, key, iv));
698+
}
699+
700+
TEST(NodeCrypto, PrivateKeyEncodingProviderOnlyCipher) {
701+
ncrypto::ClearErrorOnReturn clear_errors;
702+
const auto available = ncrypto::Cipher::FromName("AES-128-CBC-CTS");
703+
if (!available) GTEST_SKIP();
704+
const auto cipher =
705+
ncrypto::Cipher::FromNameForKeyEncoding("AES-128-CBC-CTS");
706+
ASSERT_TRUE(cipher);
707+
EXPECT_NE(EVP_CIPHER_get0_provider(cipher.get()), nullptr);
708+
EXPECT_EQ(EVP_CIPHER_is_a(cipher.get(), "AES-128-CBC-CTS"), 1);
709+
}
710+
#endif
Lines changed: 113 additions & 0 deletions

0 commit comments

Comments
 (0)