Skip to content
Closed
569 changes: 569 additions & 0 deletions deps/ncrypto/ncrypto.cc

Large diffs are not rendered by default.

196 changes: 193 additions & 3 deletions deps/ncrypto/ncrypto.h
Original file line numberDiff line numberDiff 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 DownExpand Up@@ -195,7 +196,7 @@ template <typename T, void (*function)(T*)>
using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer;

using BignumCtxPointer = DeleteFnPtr<BN_CTX, BN_CTX_free>
using CipherCtxPointer = DeleteFnPtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>
using BignumGenCallbackPointer = DeleteFnPtr<BN_GENCB, BN_GENCB_free>
using DSAPointer = DeleteFnPtr<DSA, DSA_free>
using DSASigPointer = DeleteFnPtr<DSA_SIG, DSA_SIG_free>
using ECDSASigPointer = DeleteFnPtr<ECDSA_SIG, ECDSA_SIG_free>
Expand All@@ -209,10 +210,10 @@ using HMACCtxPointer = DeleteFnPtr<HMAC_CTX, HMAC_CTX_free>
using NetscapeSPKIPointer = DeleteFnPtr<NETSCAPE_SPKI, NETSCAPE_SPKI_free>
using PKCS8Pointer = DeleteFnPtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>
using RSAPointer = DeleteFnPtr<RSA, RSA_free>
using SSLCtxPointer = DeleteFnPtr<SSL_CTX, SSL_CTX_free>
using SSLPointer = DeleteFnPtr<SSL, SSL_free>
using SSLSessionPointer = DeleteFnPtr<SSL_SESSION, SSL_SESSION_free>

class CipherCtxPointer;

struct StackOfXASN1Deleter{
void operator()(STACK_OF(ASN1_OBJECT) * p) const{
sk_ASN1_OBJECT_pop_free(p, ASN1_OBJECT_free);
Expand All@@ -227,6 +228,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;
std::string_view getModeLabel() 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 DownExpand Up@@ -272,6 +307,7 @@ class BIOPointer final{
static BIOPointer NewSecMem();
static BIOPointer New(const BIO_METHOD* method);
static BIOPointer New(const void* data, size_t len);
static BIOPointer New(const BIGNUM* bn);
static BIOPointer NewFile(std::string_view filename, std::string_view mode);
static BIOPointer NewFp(FILE* fd, int flags);

Expand DownExpand Up@@ -350,8 +386,28 @@ 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 BignumPointer NewSub(const BignumPointer& a, const BignumPointer& b);
static BignumPointer NewLShift(size_t length);

static DataPointer Encode(const BIGNUM* bn);
static DataPointer EncodePadded(const BIGNUM* bn, size_t size);
static size_t EncodePaddedInto(const BIGNUM* bn,
Expand All@@ -366,6 +422,53 @@ class BignumPointer final{

private:
DeleteFnPtr<BIGNUM, BN_clear_free> bn_;

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

class CipherCtxPointer final{
public:
static CipherCtxPointer New();

CipherCtxPointer() = default;
explicit CipherCtxPointer(EVP_CIPHER_CTX* ctx);
CipherCtxPointer(CipherCtxPointer&& other) noexcept;
CipherCtxPointer& operator=(CipherCtxPointer&& other) noexcept;
NCRYPTO_DISALLOW_COPY(CipherCtxPointer)
~CipherCtxPointer();

inline bool operator==(std::nullptr_t) const noexcept{
return ctx_ == nullptr;
}
inline operator bool() const{return ctx_ != nullptr}
inline EVP_CIPHER_CTX* get() const{return ctx_.get()}
inline operator EVP_CIPHER_CTX*() const{return ctx_.get()}
void reset(EVP_CIPHER_CTX* ctx = nullptr);
EVP_CIPHER_CTX* release();

void setFlags(int flags);
bool setKeyLength(size_t length);
bool setIvLength(size_t length);
bool setAeadTag(const Buffer<const char>& tag);
bool setAeadTagLength(size_t length);
bool setPadding(bool padding);
bool init(const Cipher& cipher,
bool encrypt,
const unsigned char* key = nullptr,
const unsigned char* iv = nullptr);

int getBlockSize() const;
int getMode() const;
int getNid() const;

bool update(const Buffer<const unsigned char>& in,
unsigned char* out,
int* out_len,
bool finalize = false);
bool getAeadTag(size_t len, unsigned char* out);

private:
DeleteFnPtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free> ctx_;
};

class EVPKeyPointer final{
Expand DownExpand Up@@ -551,7 +654,85 @@ class DHPointer final{
DeleteFnPtr<DH, DH_free> dh_;
};

struct StackOfX509Deleter{
void operator()(STACK_OF(X509) * p) const{sk_X509_pop_free(p, X509_free)}
};
using StackOfX509 = std::unique_ptr<STACK_OF(X509), StackOfX509Deleter>

class X509Pointer;
class X509View;

class SSLCtxPointer final{
public:
SSLCtxPointer() = default;
explicit SSLCtxPointer(SSL_CTX* ctx);
SSLCtxPointer(SSLCtxPointer&& other) noexcept;
SSLCtxPointer& operator=(SSLCtxPointer&& other) noexcept;
NCRYPTO_DISALLOW_COPY(SSLCtxPointer)
~SSLCtxPointer();

inline bool operator==(std::nullptr_t) const noexcept{
return ctx_ == nullptr;
}
inline operator bool() const{return ctx_ != nullptr}
inline SSL_CTX* get() const{return ctx_.get()}
void reset(SSL_CTX* ctx = nullptr);
void reset(const SSL_METHOD* method);
SSL_CTX* release();

bool setGroups(const char* groups);
void setStatusCallback(auto callback){
if (!ctx_) return;
SSL_CTX_set_tlsext_status_cb(get(), callback);
SSL_CTX_set_tlsext_status_arg(get(), nullptr);
}

static SSLCtxPointer NewServer();
static SSLCtxPointer NewClient();
static SSLCtxPointer New(const SSL_METHOD* method = TLS_method());

private:
DeleteFnPtr<SSL_CTX, SSL_CTX_free> ctx_;
};

class SSLPointer final{
public:
SSLPointer() = default;
explicit SSLPointer(SSL* ssl);
SSLPointer(SSLPointer&& other) noexcept;
SSLPointer& operator=(SSLPointer&& other) noexcept;
NCRYPTO_DISALLOW_COPY(SSLPointer)
~SSLPointer();

inline bool operator==(std::nullptr_t) noexcept{return ssl_ == nullptr}
inline operator bool() const{return ssl_ != nullptr}
inline SSL* get() const{return ssl_.get()}
inline operator SSL*() const{return ssl_.get()}
void reset(SSL* ssl = nullptr);
SSL* release();

bool setSession(const SSLSessionPointer& session);
bool setSniContext(const SSLCtxPointer& ctx) const;

const std::string_view getClientHelloAlpn() const;
const std::string_view getClientHelloServerName() const;

std::optional<const std::string_view> getServerName() const;
X509View getCertificate() const;
EVPKeyPointer getPeerTempKey() const;
const SSL_CIPHER* getCipher() const;
bool isServer() const;

std::optional<uint32_t> verifyPeerCertificate() const;

void getCiphers(std::function<void(const std::string_view)> cb) const;

static SSLPointer New(const SSLCtxPointer& ctx);
static std::optional<const std::string_view> GetServerName(const SSL* ssl);

private:
DeleteFnPtr<SSL, SSL_free> ssl_;
};

class X509View final{
public:
Expand All@@ -565,6 +746,8 @@ class X509View final{
NCRYPTO_DISALLOW_MOVE(X509View)

inline X509* get() const{return const_cast<X509*>(cert_)}
inline operator X509*() const{return const_cast<X509*>(cert_)}
inline operator const X509*() const{return cert_}

inline bool operator==(std::nullptr_t) noexcept{return cert_ == nullptr}
inline operator bool() const{return cert_ != nullptr}
Expand All@@ -589,6 +772,8 @@ class X509View final{
bool checkPrivateKey(const EVPKeyPointer& pkey) const;
bool checkPublicKey(const EVPKeyPointer& pkey) const;

std::optional<std::string> getFingerprint(const EVP_MD* method) const;

X509Pointer clone() const;

enum class CheckMatch{
Expand DownExpand Up@@ -624,12 +809,17 @@ class X509Pointer final{
inline bool operator==(std::nullptr_t) noexcept{return cert_ == nullptr}
inline operator bool() const{return cert_ != nullptr}
inline X509* get() const{return cert_.get()}
inline operator X509*() const{return cert_.get()}
inline operator const X509*() const{return cert_.get()}
void reset(X509* cert = nullptr);
X509* release();

X509View view() const;
operator X509View() const{return view()}

static std::string_view ErrorCode(int32_t err);
static std::optional<std::string_view> ErrorReason(int32_t err);

private:
DeleteFnPtr<X509, X509_free> cert_;
};
Expand Down
Loading
Loading