Skip to content

Commit

Permalink
src: shift more crypto impl details to ncrypto
Browse files Browse the repository at this point in the history
PR-URL: nodejs#54028
Reviewed-By: Yagiz Nizipli <[email protected]>
  • Loading branch information
jasnell committed Aug 5, 2024
1 parent c6aeddf commit 926503b
Show file tree
Hide file tree
Showing 14 changed files with 653 additions and 479 deletions.
460 changes: 437 additions & 23 deletions deps/ncrypto/ncrypto.cc

Large diffs are not rendered by default.

98 changes: 83 additions & 15 deletions deps/ncrypto/ncrypto.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#pragma once

#include <cstddef>
#include <list>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include "openssl/bn.h"
#include <openssl/x509.h>
#include <openssl/dh.h>
Expand Down Expand Up @@ -82,6 +82,15 @@ namespace ncrypto {
void* operator new(size_t) = delete; \
void operator delete(void*) = delete;

[[noreturn]] inline void unreachable() {
#ifdef __GNUC__
__builtin_unreachable();
#elif defined(_MSC_VER)
__assume(false);
#else
#endif
}

// ============================================================================
// Error handling utilities

Expand Down Expand Up @@ -190,30 +199,92 @@ using SSLPointer = DeleteFnPtr<SSL, SSL_free>;
using SSLSessionPointer = DeleteFnPtr<SSL_SESSION, SSL_SESSION_free>;
using X509Pointer = DeleteFnPtr<X509, X509_free>;

// An unowned, unmanaged pointer to a buffer of data.
template <typename T>
struct Buffer {
T* data = nullptr;
size_t len = 0;
};

// A managed pointer to a buffer of data. When destroyed the underlying
// buffer will be freed.
class DataPointer final {
public:
static DataPointer Alloc(size_t len);

DataPointer() = default;
explicit DataPointer(void* data, size_t len);
explicit DataPointer(const Buffer<void>& buffer);
DataPointer(DataPointer&& other) noexcept;
DataPointer& operator=(DataPointer&& other) noexcept;
NCRYPTO_DISALLOW_COPY(DataPointer)
~DataPointer();

inline bool operator==(std::nullptr_t) noexcept { return data_ == nullptr; }
inline operator bool() const { return data_ != nullptr; }
inline void* get() const noexcept { return data_; }
inline size_t size() const noexcept { return len_; }
void reset(void* data = nullptr, size_t len = 0);
void reset(const Buffer<void>& buffer);

// Releases ownership of the underlying data buffer. It is the caller's
// responsibility to ensure the buffer is appropriately freed.
Buffer<void> release();

// Returns a Buffer struct that is a view of the underlying data.
inline operator const Buffer<void>() const {
return {
.data = data_,
.len = len_,
};
}

private:
void* data_ = nullptr;
size_t len_ = 0;
};

class BignumPointer final {
public:
BignumPointer() = default;
explicit BignumPointer(BIGNUM* bignum);
explicit BignumPointer(const unsigned char* data, size_t len);
BignumPointer(BignumPointer&& other) noexcept;
BignumPointer& operator=(BignumPointer&& other) noexcept;
NCRYPTO_DISALLOW_COPY(BignumPointer)
~BignumPointer();

bool operator==(const BignumPointer& other) noexcept;
bool operator==(const BIGNUM* other) noexcept;
inline bool operator==(std::nullptr_t) noexcept { return bn_ == nullptr; }
int operator<=>(const BignumPointer& other) const noexcept;
int operator<=>(const BIGNUM* other) const noexcept;
inline operator bool() const { return bn_ != nullptr; }
inline BIGNUM* get() const noexcept { return bn_.get(); }
void reset(BIGNUM* bn = nullptr);
void reset(const unsigned char* data, size_t len);
BIGNUM* release();

size_t byteLength();
bool isZero() const;
bool isOne() const;

std::vector<uint8_t> encode();
std::vector<uint8_t> encodePadded(size_t size);
bool setWord(unsigned long w);
unsigned long getWord() const;

static std::vector<uint8_t> encode(const BIGNUM* bn);
static std::vector<uint8_t> encodePadded(const BIGNUM* bn, size_t size);
size_t byteLength() const;

DataPointer toHex() const;
DataPointer encode() const;
DataPointer encodePadded(size_t size) const;
size_t encodeInto(unsigned char* out) const;
size_t encodePaddedInto(unsigned char* out, size_t size) const;

static BignumPointer New();
static BignumPointer NewSecure();
static DataPointer Encode(const BIGNUM* bn);
static DataPointer EncodePadded(const BIGNUM* bn, size_t size);
static size_t EncodePaddedInto(const BIGNUM* bn, unsigned char* out, size_t size);
static int GetBitCount(const BIGNUM* bn);
static int GetByteCount(const BIGNUM* bn);
static unsigned long GetWord(const BIGNUM* bn);
static const BIGNUM* One();

private:
DeleteFnPtr<BIGNUM, BN_clear_free> bn_;
Expand Down Expand Up @@ -269,12 +340,6 @@ bool testFipsEnabled();
// ============================================================================
// Various utilities

template <typename T>
struct Buffer {
T* data = nullptr;
size_t len = 0;
};

bool CSPRNG(void* buffer, size_t length) NCRYPTO_MUST_USE_RESULT;

// This callback is used to avoid the default passphrase callback in OpenSSL
Expand All @@ -286,6 +351,9 @@ int NoPasswordCallback(char* buf, int size, int rwflag, void* u);

int PasswordCallback(char* buf, int size, int rwflag, void* u);

bool SafeX509SubjectAltNamePrint(const BIOPointer& out, X509_EXTENSION* ext);
bool SafeX509InfoAccessPrint(const BIOPointer& out, X509_EXTENSION* ext);

// ============================================================================
// SPKAC

Expand Down
25 changes: 10 additions & 15 deletions src/crypto/crypto_aes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,7 @@ BignumPointer GetCounter(const AESCipherConfig& params) {

if (remainder == 0) {
unsigned int byte_length = params.length / CHAR_BIT;
return BignumPointer(BN_bin2bn(
data + params.iv.size() - byte_length,
byte_length,
nullptr));
return BignumPointer(data + params.iv.size() - byte_length, byte_length);
}

unsigned int byte_length =
Expand All @@ -199,7 +196,7 @@ BignumPointer GetCounter(const AESCipherConfig& params) {
data + params.iv.size());
counter[0] &= ~(0xFF << remainder);

return BignumPointer(BN_bin2bn(counter.data(), counter.size(), nullptr));
return BignumPointer(counter.data(), counter.size());
}

std::vector<unsigned char> BlockWithZeroedCounter(
Expand Down Expand Up @@ -269,23 +266,22 @@ WebCryptoCipherStatus AES_CTR_Cipher(
const AESCipherConfig& params,
const ByteSource& in,
ByteSource* out) {
BignumPointer num_counters(BN_new());
if (!BN_lshift(num_counters.get(), BN_value_one(), params.length))
auto num_counters = BignumPointer::New();
if (!BN_lshift(num_counters.get(), BignumPointer::One(), params.length))
return WebCryptoCipherStatus::FAILED;

BignumPointer current_counter = GetCounter(params);

BignumPointer num_output(BN_new());
auto num_output = BignumPointer::New();

if (!BN_set_word(num_output.get(), CeilDiv(in.size(), kAesBlockSize)))
if (!num_output.setWord(CeilDiv(in.size(), kAesBlockSize)))
return WebCryptoCipherStatus::FAILED;

// Just like in chromium's implementation, if the counter will
// be incremented more than there are counter values, we fail.
if (BN_cmp(num_output.get(), num_counters.get()) > 0)
return WebCryptoCipherStatus::FAILED;
if (num_output > num_counters) return WebCryptoCipherStatus::FAILED;

BignumPointer remaining_until_reset(BN_new());
auto remaining_until_reset = BignumPointer::New();
if (!BN_sub(remaining_until_reset.get(),
num_counters.get(),
current_counter.get())) {
Expand All @@ -298,7 +294,7 @@ WebCryptoCipherStatus AES_CTR_Cipher(
// Also just like in chromium's implementation, if we can process
// the input without wrapping the counter, we'll do it as a single
// call here. If we can't, we'll fallback to the a two-step approach
if (BN_cmp(remaining_until_reset.get(), num_output.get()) >= 0) {
if (remaining_until_reset >= num_output) {
auto status = AES_CTR_Cipher2(key_data,
cipher_mode,
params,
Expand All @@ -309,8 +305,7 @@ WebCryptoCipherStatus AES_CTR_Cipher(
return status;
}

BN_ULONG blocks_part1 = BN_get_word(remaining_until_reset.get());
BN_ULONG input_size_part1 = blocks_part1 * kAesBlockSize;
BN_ULONG input_size_part1 = remaining_until_reset.getWord() * kAesBlockSize;

// Encrypt the first part...
auto status =
Expand Down
Loading

0 comments on commit 926503b

Please sign in to comment.