Skip to content

Commit

Permalink
src, deps: port electron's boringssl workarounds
Browse files Browse the repository at this point in the history
Signed-off-by: James M Snell <jasnell@gmail.com>
PR-URL: #56812
Reviewed-By: Shelley Vohr <shelley.vohr@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
  • Loading branch information
jasnell committed Feb 4, 2025
1 parent 2388d61 commit 206ebeb
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 6 deletions.
100 changes: 94 additions & 6 deletions deps/ncrypto/ncrypto.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "ncrypto.h"
#include <openssl/asn1.h>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/evp.h>
Expand Down Expand Up @@ -99,7 +100,15 @@ std::optional<std::string> CryptoErrorList::pop_front() {

// ============================================================================
DataPointer DataPointer::Alloc(size_t len) {
#ifdef OPENSSL_IS_BORINGSSL
// Boringssl does not implement OPENSSL_zalloc
auto ptr = OPENSSL_malloc(len);
if (ptr == nullptr) return {};
memset(ptr, 0, len);
return DataPointer(ptr, len);
#else
return DataPointer(OPENSSL_zalloc(len), len);
#endif
}

DataPointer DataPointer::Copy(const Buffer<const void>& buffer) {
Expand Down Expand Up @@ -218,7 +227,12 @@ BignumPointer BignumPointer::New() {
}

BignumPointer BignumPointer::NewSecure() {
#ifdef OPENSSL_IS_BORINGSSL
// Boringssl does not implement BN_secure_new.
return New();
#else
return BignumPointer(BN_secure_new());
#endif
}

BignumPointer& BignumPointer::operator=(BignumPointer&& other) noexcept {
Expand Down Expand Up @@ -492,6 +506,7 @@ constexpr int days_from_epoch(int y, unsigned m, unsigned d) {
return era * 146097 + static_cast<int>(doe) - 719468;
}

#ifndef OPENSSL_IS_BORINGSSL
// tm must be in UTC
// using time_t causes problems on 32-bit systems and windows x64.
int64_t PortableTimeGM(struct tm* t) {
Expand All @@ -512,6 +527,7 @@ int64_t PortableTimeGM(struct tm* t) {
t->tm_min) +
t->tm_sec;
}
#endif

// ============================================================================
// SPKAC
Expand Down Expand Up @@ -822,7 +838,7 @@ bool SafeX509SubjectAltNamePrint(const BIOPointer& out, X509_EXTENSION* ext) {

bool ok = true;

for (int i = 0; i < sk_GENERAL_NAME_num(names); i++) {
for (OPENSSL_SIZE_T i = 0; i < sk_GENERAL_NAME_num(names); i++) {
GENERAL_NAME* gen = sk_GENERAL_NAME_value(names, i);

if (i != 0) BIO_write(out.get(), ", ", 2);
Expand All @@ -846,7 +862,7 @@ bool SafeX509InfoAccessPrint(const BIOPointer& out, X509_EXTENSION* ext) {

bool ok = true;

for (int i = 0; i < sk_ACCESS_DESCRIPTION_num(descs); i++) {
for (OPENSSL_SIZE_T i = 0; i < sk_ACCESS_DESCRIPTION_num(descs); i++) {
ACCESS_DESCRIPTION* desc = sk_ACCESS_DESCRIPTION_value(descs, i);

if (i != 0) BIO_write(out.get(), "\n", 1);
Expand Down Expand Up @@ -999,15 +1015,31 @@ BIOPointer X509View::getValidTo() const {
}

int64_t X509View::getValidToTime() const {
#ifdef OPENSSL_IS_BORINGSSL
// Boringssl does not implement ASN1_TIME_to_tm in a public way,
// and only recently added ASN1_TIME_to_posix. Some boringssl
// users on older version may still need to patch around this
// or use a different implementation.
int64_t tp;
ASN1_TIME_to_posix(X509_get0_notAfter(cert_), &tp);
return tp;
#else
struct tm tp;
ASN1_TIME_to_tm(X509_get0_notAfter(cert_), &tp);
return PortableTimeGM(&tp);
#endif
}

int64_t X509View::getValidFromTime() const {
#ifdef OPENSSL_IS_BORINGSSL
int64_t tp;
ASN1_TIME_to_posix(X509_get0_notBefore(cert_), &tp);
return tp;
#else
struct tm tp;
ASN1_TIME_to_tm(X509_get0_notBefore(cert_), &tp);
return PortableTimeGM(&tp);
#endif
}

DataPointer X509View::getSerialNumber() const {
Expand Down Expand Up @@ -1324,7 +1356,12 @@ BIOPointer BIOPointer::NewMem() {
}

BIOPointer BIOPointer::NewSecMem() {
#ifdef OPENSSL_IS_BORINGSSL
// Boringssl does not implement the BIO_s_secmem API.
return BIOPointer(BIO_new(BIO_s_mem()));
#else
return BIOPointer(BIO_new(BIO_s_secmem()));
#endif
}

BIOPointer BIOPointer::New(const BIO_METHOD* method) {
Expand Down Expand Up @@ -1394,8 +1431,11 @@ BignumPointer DHPointer::FindGroup(const std::string_view name,
#define V(n, p) \
if (EqualNoCase(name, n)) return BignumPointer(p(nullptr));
if (option != FindGroupOption::NO_SMALL_PRIMES) {
#ifndef OPENSSL_IS_BORINGSSL
// Boringssl does not support the 768 and 1024 small primes
V("modp1", BN_get_rfc2409_prime_768);
V("modp2", BN_get_rfc2409_prime_1024);
#endif
V("modp5", BN_get_rfc3526_prime_1536);
}
V("modp14", BN_get_rfc3526_prime_2048);
Expand Down Expand Up @@ -1467,15 +1507,22 @@ DHPointer::CheckResult DHPointer::check() {
DHPointer::CheckPublicKeyResult DHPointer::checkPublicKey(
const BignumPointer& pub_key) {
ClearErrorOnReturn clearErrorOnReturn;
if (!pub_key || !dh_) return DHPointer::CheckPublicKeyResult::CHECK_FAILED;
if (!pub_key || !dh_) {
return DHPointer::CheckPublicKeyResult::CHECK_FAILED;
}
int codes = 0;
if (DH_check_pub_key(dh_.get(), pub_key.get(), &codes) != 1)
if (DH_check_pub_key(dh_.get(), pub_key.get(), &codes) != 1) {
return DHPointer::CheckPublicKeyResult::CHECK_FAILED;
}
#ifndef OPENSSL_IS_BORINGSSL
// Boringssl does not define DH_CHECK_PUBKEY_TOO_SMALL or TOO_LARGE
if (codes & DH_CHECK_PUBKEY_TOO_SMALL) {
return DHPointer::CheckPublicKeyResult::TOO_SMALL;
} else if (codes & DH_CHECK_PUBKEY_TOO_SMALL) {
} else if (codes & DH_CHECK_PUBKEY_TOO_LARGE) {
return DHPointer::CheckPublicKeyResult::TOO_LARGE;
} else if (codes != 0) {
}
#endif
if (codes != 0) {
return DHPointer::CheckPublicKeyResult::INVALID;
}
return CheckPublicKeyResult::NONE;
Expand Down Expand Up @@ -2530,6 +2577,7 @@ std::optional<uint32_t> SSLPointer::verifyPeerCertificate() const {

const std::string_view SSLPointer::getClientHelloAlpn() const {
if (ssl_ == nullptr) return {};
#ifndef OPENSSL_IS_BORINGSSL
const unsigned char* buf;
size_t len;
size_t rem;
Expand All @@ -2546,10 +2594,15 @@ const std::string_view SSLPointer::getClientHelloAlpn() const {
len = (buf[0] << 8) | buf[1];
if (len + 2 != rem) return {};
return reinterpret_cast<const char*>(buf + 3);
#else
// Boringssl doesn't have a public API for this.
return {};
#endif
}

const std::string_view SSLPointer::getClientHelloServerName() const {
if (ssl_ == nullptr) return {};
#ifndef OPENSSL_IS_BORINGSSL
const unsigned char* buf;
size_t len;
size_t rem;
Expand All @@ -2569,6 +2622,10 @@ const std::string_view SSLPointer::getClientHelloServerName() const {
len = (*(buf + 3) << 8) | *(buf + 4);
if (len + 2 > rem) return {};
return reinterpret_cast<const char*>(buf + 5);
#else
// Boringssl doesn't have a public API for this.
return {};
#endif
}

std::optional<const std::string_view> SSLPointer::GetServerName(
Expand Down Expand Up @@ -2602,7 +2659,11 @@ bool SSLPointer::isServer() const {
EVPKeyPointer SSLPointer::getPeerTempKey() const {
if (!ssl_) return {};
EVP_PKEY* raw_key = nullptr;
#ifndef OPENSSL_IS_BORINGSSL
if (!SSL_get_peer_tmp_key(get(), &raw_key)) return {};
#else
if (!SSL_get_server_tmp_key(get(), &raw_key)) return {};
#endif
return EVPKeyPointer(raw_key);
}

Expand Down Expand Up @@ -3167,9 +3228,15 @@ int EVPKeyCtxPointer::initForSign() {
}

bool EVPKeyCtxPointer::setDhParameters(int prime_size, uint32_t generator) {
#ifndef OPENSSL_IS_BORINGSSL
if (!ctx_) return false;
return EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx_.get(), prime_size) == 1 &&
EVP_PKEY_CTX_set_dh_paramgen_generator(ctx_.get(), generator) == 1;
#else
// TODO(jasnell): Boringssl appears not to support this operation.
// Is there an alternative approach that Boringssl does support?
return false;
#endif
}

bool EVPKeyCtxPointer::setDsaParameters(uint32_t bits,
Expand Down Expand Up @@ -3249,6 +3316,7 @@ bool EVPKeyCtxPointer::setRsaPssSaltlen(int salt_len) {
}

bool EVPKeyCtxPointer::setRsaImplicitRejection() {
#ifndef OPENSSL_IS_BORINGSSL
if (!ctx_) return false;
return EVP_PKEY_CTX_ctrl_str(
ctx_.get(), "rsa_pkcs1_implicit_rejection", "1") > 0;
Expand All @@ -3259,6 +3327,11 @@ bool EVPKeyCtxPointer::setRsaImplicitRejection() {
// of how it is set. The call to set the value
// will not affect what is used since a different context is
// used in the call if the option is supported
#else
// TODO(jasnell): Boringssl appears not to support this operation.
// Is there an alternative approach that Boringssl does support?
return true;
#endif
}

bool EVPKeyCtxPointer::setRsaOaepLabel(DataPointer&& data) {
Expand Down Expand Up @@ -3311,16 +3384,31 @@ EVPKeyPointer EVPKeyCtxPointer::paramgen() const {

bool EVPKeyCtxPointer::publicCheck() const {
if (!ctx_) return false;
#ifndef OPENSSL_IS_BORINGSSL
return EVP_PKEY_public_check(ctx_.get()) == 1;
#if OPENSSL_VERSION_MAJOR >= 3
return EVP_PKEY_public_check_quick(ctx_.get()) == 1;
#else
return EVP_PKEY_public_check(ctx_.get()) == 1;
#endif
#else // OPENSSL_IS_BORINGSSL
// Boringssl appears not to support this operation.
// TODO(jasnell): Is there an alternative approach that Boringssl does
// support?
return true;
#endif
}

bool EVPKeyCtxPointer::privateCheck() const {
if (!ctx_) return false;
#ifndef OPENSSL_IS_BORINGSSL
return EVP_PKEY_check(ctx_.get()) == 1;
#else
// Boringssl appears not to support this operation.
// TODO(jasnell): Is there an alternative approach that Boringssl does
// support?
return true;
#endif
}

bool EVPKeyCtxPointer::verify(const Buffer<const unsigned char>& sig,
Expand Down
16 changes: 16 additions & 0 deletions deps/ncrypto/ncrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@
#define NCRYPTO_MUST_USE_RESULT
#endif

#ifdef OPENSSL_IS_BORINGSSL
// Boringssl has opted to use size_t for some size related
// APIs while Openssl is still using ints
using OPENSSL_SIZE_T = size_t;
#else
using OPENSSL_SIZE_T = int;
#endif

namespace ncrypto {

// ============================================================================
Expand Down Expand Up @@ -845,17 +853,25 @@ class DHPointer final {
UNABLE_TO_CHECK_GENERATOR = DH_UNABLE_TO_CHECK_GENERATOR,
NOT_SUITABLE_GENERATOR = DH_NOT_SUITABLE_GENERATOR,
Q_NOT_PRIME = DH_CHECK_Q_NOT_PRIME,
#ifndef OPENSSL_IS_BORINGSSL
// Boringssl does not define the DH_CHECK_INVALID_[Q or J]_VALUE
INVALID_Q = DH_CHECK_INVALID_Q_VALUE,
INVALID_J = DH_CHECK_INVALID_J_VALUE,
#endif
CHECK_FAILED = 512,
};
CheckResult check();

enum class CheckPublicKeyResult {
NONE,
#ifndef OPENSSL_IS_BORINGSSL
// Boringssl does not define DH_R_CHECK_PUBKEY_TOO_SMALL or TOO_LARGE
TOO_SMALL = DH_R_CHECK_PUBKEY_TOO_SMALL,
TOO_LARGE = DH_R_CHECK_PUBKEY_TOO_LARGE,
INVALID = DH_R_CHECK_PUBKEY_INVALID,
#else
INVALID = DH_R_INVALID_PUBKEY,
#endif
CHECK_FAILED = 512,
};
// Check to see if the given public key is suitable for this DH instance.
Expand Down

0 comments on commit 206ebeb

Please sign in to comment.