Skip to content
Closed
Prev Previous commit
Next Next commit
src: move prime gen and checks to ncrypto
  • Loading branch information
jasnell committed Jan 7, 2025
commit 1af313182267674d34b3c01927b20650af59d87a
53 changes: 53 additions & 0 deletions deps/ncrypto/ncrypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,59 @@ BignumPointer BignumPointer::clone() {
return BignumPointer(BN_dup(bn_.get()));
}

int BignumPointer::isPrime(int nchecks,
BignumPointer::PrimeCheckCallback innerCb) const {
BignumCtxPointer ctx(BN_CTX_new());
BignumGenCallbackPointer cb(nullptr);
if (innerCb != nullptr) {
cb = BignumGenCallbackPointer(BN_GENCB_new());
if (!cb) [[unlikely]] return -1;
BN_GENCB_set(cb.get(), [](int a, int b, BN_GENCB* ctx) mutable -> int {
PrimeCheckCallback& ptr =
*static_cast<PrimeCheckCallback*>(BN_GENCB_get_arg(ctx));
return ptr(a, b) ? 1 : 0;
}, &innerCb);
}
return BN_is_prime_ex(get(), nchecks, ctx.get(), cb.get());
}

BignumPointer BignumPointer::NewPrime(const PrimeConfig& params,
PrimeCheckCallback cb) {
BignumPointer prime(BN_new());
if (!prime || !prime.generate(params, std::move(cb))) {
return {};
}
return prime;
}

bool BignumPointer::generate(const PrimeConfig& params,
PrimeCheckCallback innerCb) const {
// BN_generate_prime_ex() calls RAND_bytes_ex() internally.
// Make sure the CSPRNG is properly seeded.
CSPRNG(nullptr, 0);
BignumGenCallbackPointer cb(nullptr);
if (innerCb != nullptr) {
cb = BignumGenCallbackPointer(BN_GENCB_new());
if (!cb) [[unlikely]] return -1;
BN_GENCB_set(cb.get(), [](int a, int b, BN_GENCB* ctx) mutable -> int {
PrimeCheckCallback& ptr =
*static_cast<PrimeCheckCallback*>(BN_GENCB_get_arg(ctx));
return ptr(a, b) ? 1 : 0;
}, &innerCb);
}
if (BN_generate_prime_ex(
get(),
params.bits,
params.safe ? 1 : 0,
params.add.get(),
params.rem.get(),
cb.get()) == 0) {
return false;
}

return true;
}

// ============================================================================
// Utility methods

Expand Down
20 changes: 20 additions & 0 deletions deps/ncrypto/ncrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <cstddef>
#include <functional>
#include <list>
#include <memory>
#include <optional>
Expand Down Expand Up @@ -195,6 +196,7 @@ template <typename T, void (*function)(T*)>
using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer;

using BignumCtxPointer = DeleteFnPtr<BN_CTX, BN_CTX_free>;
using BignumGenCallbackPointer = DeleteFnPtr<BN_GENCB, BN_GENCB_free>;
using CipherCtxPointer = DeleteFnPtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>;
using DSAPointer = DeleteFnPtr<DSA, DSA_free>;
using DSASigPointer = DeleteFnPtr<DSA_SIG, DSA_SIG_free>;
Expand Down Expand Up @@ -350,6 +352,22 @@ class BignumPointer final {
size_t encodeInto(unsigned char* out) const;
size_t encodePaddedInto(unsigned char* out, size_t size) const;

using PrimeCheckCallback = std::function<bool(int, int)>;
int isPrime(int checks,
PrimeCheckCallback cb = defaultPrimeCheckCallback) const;
struct PrimeConfig {
int bits;
bool safe = false;
const BignumPointer& add;
const BignumPointer& rem;
};

static BignumPointer NewPrime(const PrimeConfig& params,
PrimeCheckCallback cb = defaultPrimeCheckCallback);

bool generate(const PrimeConfig& params,
PrimeCheckCallback cb = defaultPrimeCheckCallback) const;

static BignumPointer New();
static BignumPointer NewSecure();
static DataPointer Encode(const BIGNUM* bn);
Expand All @@ -366,6 +384,8 @@ class BignumPointer final {

private:
DeleteFnPtr<BIGNUM, BN_clear_free> bn_;

static bool defaultPrimeCheckCallback(int, int) { return 1; }
};

class EVPKeyPointer final {
Expand Down
47 changes: 13 additions & 34 deletions src/crypto/crypto_random.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,13 @@ using v8::Value;

namespace crypto {
namespace {
using BNGENCBPointer = DeleteFnPtr<BN_GENCB, BN_GENCB_free>;

BNGENCBPointer getBN_GENCB(Environment* env) {
ncrypto::BignumPointer::PrimeCheckCallback getPrimeCheckCallback(Environment* env) {
// The callback is used to check if the operation should be stopped.
// Currently, the only check we perform is if env->is_stopping()
// is true.
BNGENCBPointer cb(BN_GENCB_new());
BN_GENCB_set(
cb.get(),
[](int a, int b, BN_GENCB* cb) -> int {
Environment* env = static_cast<Environment*>(BN_GENCB_get_arg(cb));
return env->is_stopping() ? 0 : 1;
},
env);
return cb;
return [env](int a, int b) -> bool {
return !env->is_stopping();
};
}

} // namespace
Expand Down Expand Up @@ -165,22 +157,13 @@ Maybe<void> RandomPrimeTraits::AdditionalConfig(
bool RandomPrimeTraits::DeriveBits(Environment* env,
const RandomPrimeConfig& params,
ByteSource* unused) {
// BN_generate_prime_ex() calls RAND_bytes_ex() internally.
// Make sure the CSPRNG is properly seeded.
CHECK(ncrypto::CSPRNG(nullptr, 0));

BNGENCBPointer cb = getBN_GENCB(env);

if (BN_generate_prime_ex(params.prime.get(),
params.bits,
params.safe ? 1 : 0,
params.add.get(),
params.rem.get(),
cb.get()) == 0) {
return false;
}

return true;
auto cb = getPrimeCheckCallback(env);
return params.prime.generate(BignumPointer::PrimeConfig {
.bits = params.bits,
.safe = params.safe,
.add = params.add,
.rem = params.rem,
}, std::move(cb));
}

void CheckPrimeConfig::MemoryInfo(MemoryTracker* tracker) const {
Expand All @@ -207,12 +190,8 @@ bool CheckPrimeTraits::DeriveBits(
Environment* env,
const CheckPrimeConfig& params,
ByteSource* out) {

BignumCtxPointer ctx(BN_CTX_new());
BNGENCBPointer cb = getBN_GENCB(env);

int ret = BN_is_prime_ex(
params.candidate.get(), params.checks, ctx.get(), cb.get());
auto cb = getPrimeCheckCallback(env);
int ret = params.candidate.isPrime(params.checks, std::move(cb));
if (ret < 0) return false;
ByteSource::Builder buf(1);
buf.data<char>()[0] = ret;
Expand Down
1 change: 0 additions & 1 deletion src/crypto/crypto_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ using EVPMDCtxPointer = ncrypto::EVPMDCtxPointer;
using RSAPointer = ncrypto::RSAPointer;
using ECPointer = ncrypto::ECPointer;
using BignumPointer = ncrypto::BignumPointer;
using BignumCtxPointer = ncrypto::BignumCtxPointer;
using NetscapeSPKIPointer = ncrypto::NetscapeSPKIPointer;
using ECGroupPointer = ncrypto::ECGroupPointer;
using ECPointPointer = ncrypto::ECPointPointer;
Expand Down