From 3c157c59c503a5f3057b822597a10622c7339c29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Sat, 13 Jun 2026 20:55:05 +0200 Subject: [PATCH] crypto,tls: do not ignore BN_get_word error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changes `BignumPointer::GetWord` such that it does not hide errors from the caller. In the context of RSA keys within X.509 certificates, we should eventually compute the public exponent correctly regardless of its size. This patch, however, is designed to be a minimal change that prevents callers from using erroneous return values of `BN_get_word`. Signed-off-by: Tobias Nießen --- deps/ncrypto/ncrypto.cc | 12 ++++++++---- deps/ncrypto/ncrypto.h | 5 +++-- src/crypto/crypto_aes.cc | 4 +++- src/crypto/crypto_x509.cc | 6 ++++-- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/deps/ncrypto/ncrypto.cc b/deps/ncrypto/ncrypto.cc index 38378b730aca66..4338dc61e025bb 100644 --- a/deps/ncrypto/ncrypto.cc +++ b/deps/ncrypto/ncrypto.cc @@ -408,12 +408,16 @@ bool BignumPointer::setWord(unsigned long w) { // NOLINT(runtime/int) return BN_set_word(bn_.get(), w) == 1; } -unsigned long BignumPointer::GetWord(const BIGNUM* bn) { // NOLINT(runtime/int) - return BN_get_word(bn); +std::optional BignumPointer::GetWord( // NOLINT(runtime/int) + const BIGNUM* bn) { + BN_ULONG ret = BN_get_word(bn); + if (ret == static_cast(-1)) return std::nullopt; + return ret; } -unsigned long BignumPointer::getWord() const { // NOLINT(runtime/int) - if (!bn_) return 0; +std::optional BignumPointer::getWord() // NOLINT(runtime/int) + const { + if (!bn_) return std::nullopt; return GetWord(bn_.get()); } diff --git a/deps/ncrypto/ncrypto.h b/deps/ncrypto/ncrypto.h index b27e2e76c3dcfc..d60244941b43a3 100644 --- a/deps/ncrypto/ncrypto.h +++ b/deps/ncrypto/ncrypto.h @@ -743,7 +743,7 @@ class BignumPointer final { bool isOne() const; bool setWord(unsigned long w); // NOLINT(runtime/int) - unsigned long getWord() const; // NOLINT(runtime/int) + std::optional getWord() const; // NOLINT(runtime/int) size_t byteLength() const; @@ -782,7 +782,8 @@ class BignumPointer final { size_t size); static int GetBitCount(const BIGNUM* bn); static int GetByteCount(const BIGNUM* bn); - static unsigned long GetWord(const BIGNUM* bn); // NOLINT(runtime/int) + static std::optional GetWord( // NOLINT(runtime/int) + const BIGNUM* bn); static const BIGNUM* One(); BignumPointer clone(); diff --git a/src/crypto/crypto_aes.cc b/src/crypto/crypto_aes.cc index 2f8f9571c6d2db..0479ab9a36de7f 100644 --- a/src/crypto/crypto_aes.cc +++ b/src/crypto/crypto_aes.cc @@ -374,7 +374,9 @@ WebCryptoCipherStatus AES_CTR_Cipher(Environment* env, return status; } - BN_ULONG input_size_part1 = remaining_until_reset.getWord() * kAesBlockSize; + std::optional remaining_blocks = remaining_until_reset.getWord(); + CHECK(remaining_blocks.has_value()); + BN_ULONG input_size_part1 = remaining_blocks.value() * kAesBlockSize; // Encrypt the first part... auto status = diff --git a/src/crypto/crypto_x509.cc b/src/crypto/crypto_x509.cc index 8082496a87714e..426b1ed7d91860 100644 --- a/src/crypto/crypto_x509.cc +++ b/src/crypto/crypto_x509.cc @@ -44,6 +44,7 @@ using v8::Local; using v8::LocalVector; using v8::MaybeLocal; using v8::NewStringType; +using v8::Null; using v8::Object; using v8::String; using v8::Uint32; @@ -688,11 +689,12 @@ MaybeLocal GetModulusString(Environment* env, const BIGNUM* n) { } MaybeLocal GetExponentString(Environment* env, const BIGNUM* e) { - uint64_t exponent_word = static_cast(BignumPointer::GetWord(e)); + auto exponent_word = BignumPointer::GetWord(e); + if (!exponent_word) return Null(env->isolate()); auto bio = BIOPointer::NewMem(); if (!bio) [[unlikely]] return {}; - BIO_printf(bio.get(), "0x%" PRIx64, exponent_word); + BIO_printf(bio.get(), "0x%" PRIx64, static_cast(*exponent_word)); return ToV8Value(env->context(), bio); }