Skip to content

Commit

Permalink
src: move EVP_CIPHER methods to ncrypto
Browse files Browse the repository at this point in the history
  • Loading branch information
jasnell committed Jan 2, 2025
1 parent f2756bd commit e6b27ca
Show file tree
Hide file tree
Showing 9 changed files with 264 additions and 171 deletions.
179 changes: 135 additions & 44 deletions deps/ncrypto/ncrypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -312,23 +312,27 @@ BignumPointer BignumPointer::clone() {
}

int BignumPointer::isPrime(int nchecks,
BignumPointer::PrimeCheckCallback innerCb) const {
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);
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) {
PrimeCheckCallback cb) {
BignumPointer prime(BN_new());
if (!prime || !prime.generate(params, std::move(cb))) {
return {};
Expand All @@ -337,27 +341,30 @@ BignumPointer BignumPointer::NewPrime(const PrimeConfig& params,
}

bool BignumPointer::generate(const PrimeConfig& params,
PrimeCheckCallback innerCb) const {
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) {
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;
}

Expand Down Expand Up @@ -2228,13 +2235,11 @@ void SSLPointer::getCiphers(
// document them, but since there are only 5, easier to just add them manually
// and not have to explain their absence in the API docs. They are lower-cased
// because the docs say they will be.
static const char* TLS13_CIPHERS[] = {
"tls_aes_256_gcm_sha384",
"tls_chacha20_poly1305_sha256",
"tls_aes_128_gcm_sha256",
"tls_aes_128_ccm_8_sha256",
"tls_aes_128_ccm_sha256"
};
static const char* TLS13_CIPHERS[] = {"tls_aes_256_gcm_sha384",
"tls_chacha20_poly1305_sha256",
"tls_aes_128_gcm_sha256",
"tls_aes_128_ccm_8_sha256",
"tls_aes_128_ccm_sha256"};

const int n = sk_SSL_CIPHER_num(ciphers);

Expand All @@ -2259,7 +2264,7 @@ bool SSLPointer::setSniContext(const SSLCtxPointer& ctx) const {
auto x509 = ncrypto::X509View::From(ctx);
if (!x509) return false;
EVP_PKEY* pkey = SSL_CTX_get0_privatekey(ctx.get());
STACK_OF(X509)* chain;
STACK_OF(X509) * chain;

int err = SSL_CTX_get0_chain_certs(ctx.get(), &chain);
if (err == 1) err = SSL_use_certificate(get(), x509);
Expand All @@ -2281,7 +2286,7 @@ std::optional<uint32_t> SSLPointer::verifyPeerCertificate() const {
// looks like session resumption.
if (SSL_CIPHER_get_auth_nid(curr_cipher) == NID_auth_psk ||
(SSL_SESSION_get_protocol_version(sess) == TLS1_3_VERSION &&
SSL_session_reused(get()))) {
SSL_session_reused(get()))) {
return X509_V_OK;
}

Expand Down Expand Up @@ -2314,26 +2319,20 @@ const std::string_view SSLPointer::getClientHelloServerName() const {
size_t len;
size_t rem;

if (!SSL_client_hello_get0_ext(
get(),
TLSEXT_TYPE_server_name,
&buf,
&rem) || rem <= 2) {
if (!SSL_client_hello_get0_ext(get(), TLSEXT_TYPE_server_name, &buf, &rem) ||
rem <= 2) {
return nullptr;
}

len = (*buf << 8) | *(buf + 1);
if (len + 2 != rem)
return nullptr;
if (len + 2 != rem) return nullptr;
rem = len;

if (rem == 0 || *(buf + 2) != TLSEXT_NAMETYPE_host_name) return nullptr;
rem--;
if (rem <= 2)
return nullptr;
if (rem <= 2) return nullptr;
len = (*(buf + 3) << 8) | *(buf + 4);
if (len + 2 > rem)
return nullptr;
if (len + 2 > rem) return nullptr;
return reinterpret_cast<const char*>(buf + 5);
}

Expand Down Expand Up @@ -2383,7 +2382,9 @@ SSLCtxPointer& SSLCtxPointer::operator=(SSLCtxPointer&& other) noexcept {
return *new (this) SSLCtxPointer(std::move(other));
}

SSLCtxPointer::~SSLCtxPointer() { reset(); }
SSLCtxPointer::~SSLCtxPointer() {
reset();
}

void SSLCtxPointer::reset(SSL_CTX* ctx) {
ctx_.reset(ctx);
Expand Down Expand Up @@ -2413,4 +2414,94 @@ bool SSLCtxPointer::setGroups(const char* groups) {
return SSL_CTX_set1_groups_list(get(), groups) == 1;
}

// ============================================================================

const Cipher Cipher::FromName(const char* name) {
return Cipher(EVP_get_cipherbyname(name));
}

const Cipher Cipher::FromNid(int nid) {
return Cipher(EVP_get_cipherbynid(nid));
}

const Cipher Cipher::FromCtx(const CipherCtxPointer& ctx) {
return Cipher(EVP_CIPHER_CTX_cipher(ctx.get()));
}

int Cipher::getMode() const {
if (!cipher_) return 0;
return EVP_CIPHER_mode(cipher_);
}

int Cipher::getIvLength() const {
if (!cipher_) return 0;
return EVP_CIPHER_iv_length(cipher_);
}

int Cipher::getKeyLength() const {
if (!cipher_) return 0;
return EVP_CIPHER_key_length(cipher_);
}

int Cipher::getBlockSize() const {
if (!cipher_) return 0;
return EVP_CIPHER_block_size(cipher_);
}

int Cipher::getNid() const {
if (!cipher_) return 0;
return EVP_CIPHER_nid(cipher_);
}

const std::string_view Cipher::getModeLabel() const {
if (!cipher_) return {};
switch (getMode()) {
case EVP_CIPH_CCM_MODE:
return "ccm";
case EVP_CIPH_CFB_MODE:
return "cfb";
case EVP_CIPH_CBC_MODE:
return "cbc";
case EVP_CIPH_CTR_MODE:
return "ctr";
case EVP_CIPH_ECB_MODE:
return "ecb";
case EVP_CIPH_GCM_MODE:
return "gcm";
case EVP_CIPH_OCB_MODE:
return "ocb";
case EVP_CIPH_OFB_MODE:
return "ofb";
case EVP_CIPH_WRAP_MODE:
return "wrap";
case EVP_CIPH_XTS_MODE:
return "xts";
case EVP_CIPH_STREAM_CIPHER:
return "stream";
}
return "{unknown}";
}

const std::string_view Cipher::getName() const {
if (!cipher_) return {};
// OBJ_nid2sn(EVP_CIPHER_nid(cipher)) is used here instead of
// EVP_CIPHER_name(cipher) for compatibility with BoringSSL.
return OBJ_nid2sn(getNid());
}

bool Cipher::isSupportedAuthenticatedMode() const {
switch (getMode()) {
case EVP_CIPH_CCM_MODE:
case EVP_CIPH_GCM_MODE:
#ifndef OPENSSL_NO_OCB
case EVP_CIPH_OCB_MODE:
#endif
return true;
case EVP_CIPH_STREAM_CIPHER:
return getNid() == NID_chacha20_poly1305;
default:
return false;
}
}

} // namespace ncrypto
41 changes: 38 additions & 3 deletions deps/ncrypto/ncrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,40 @@ struct Buffer {
size_t len = 0;
};

class Cipher final {
public:
Cipher() = default;
Cipher(const EVP_CIPHER* cipher) : cipher_(cipher) {}
Cipher(const Cipher&) = default;
Cipher& operator=(const Cipher&) = default;
inline Cipher& operator=(const EVP_CIPHER* cipher) {
cipher_ = cipher;
return *this;
}
NCRYPTO_DISALLOW_MOVE(Cipher)

inline const EVP_CIPHER* get() const { return cipher_; }
inline operator const EVP_CIPHER*() const { return cipher_; }
inline operator bool() const { return cipher_ != nullptr; }

int getNid() const;
int getMode() const;
int getIvLength() const;
int getKeyLength() const;
int getBlockSize() const;
const std::string_view getModeLabel() const;
const std::string_view getName() const;

bool isSupportedAuthenticatedMode() const;

static const Cipher FromName(const char* name);
static const Cipher FromNid(int nid);
static const Cipher FromCtx(const CipherCtxPointer& ctx);

private:
const EVP_CIPHER* cipher_ = nullptr;
};

// A managed pointer to a buffer of data. When destroyed the underlying
// buffer will be freed.
class DataPointer final {
Expand Down Expand Up @@ -353,19 +387,20 @@ class BignumPointer final {

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

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

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

static BignumPointer New();
static BignumPointer NewSecure();
Expand Down
11 changes: 5 additions & 6 deletions src/crypto/crypto_aes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ WebCryptoCipherStatus AES_Cipher(Environment* env,
ByteSource* out) {
CHECK_EQ(key_data.GetKeyType(), kKeyTypeSecret);

const int mode = EVP_CIPHER_mode(params.cipher);
const int mode = params.cipher.getMode();

CipherCtxPointer ctx(EVP_CIPHER_CTX_new());
EVP_CIPHER_CTX_init(ctx.get());
Expand Down Expand Up @@ -478,13 +478,13 @@ Maybe<void> AESCipherTraits::AdditionalConfig(
}
#undef V

params->cipher = EVP_get_cipherbynid(cipher_nid);
if (params->cipher == nullptr) {
params->cipher = ncrypto::Cipher::FromNid(cipher_nid);
if (!params->cipher) {
THROW_ERR_CRYPTO_UNKNOWN_CIPHER(env);
return Nothing<void>();
}

int cipher_op_mode = EVP_CIPHER_mode(params->cipher);
int cipher_op_mode = params->cipher.getMode();
if (cipher_op_mode != EVP_CIPH_WRAP_MODE) {
if (!ValidateIV(env, mode, args[offset + 1], params)) {
return Nothing<void>();
Expand All @@ -503,8 +503,7 @@ Maybe<void> AESCipherTraits::AdditionalConfig(
UseDefaultIV(params);
}

if (params->iv.size() <
static_cast<size_t>(EVP_CIPHER_iv_length(params->cipher))) {
if (params->iv.size() < static_cast<size_t>(params->cipher.getIvLength())) {
THROW_ERR_CRYPTO_INVALID_IV(env);
return Nothing<void>();
}
Expand Down
2 changes: 1 addition & 1 deletion src/crypto/crypto_aes.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ enum AESKeyVariant {
struct AESCipherConfig final : public MemoryRetainer {
CryptoJobMode mode;
AESKeyVariant variant;
const EVP_CIPHER* cipher;
ncrypto::Cipher cipher;
size_t length;
ByteSource iv; // Used for both iv or counter
ByteSource additional_data;
Expand Down
Loading

0 comments on commit e6b27ca

Please sign in to comment.