Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions build/cmake/ConfigureChecks.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,34 @@ set(PACKAGE ${PACKAGE_NAME})
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(VERSION ${thrift_VERSION})

if(WITH_OPENSSL AND OPENSSL_FOUND)
set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}")
if(TARGET OpenSSL::SSL AND TARGET OpenSSL::Crypto)
set(CMAKE_REQUIRED_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
else()
set(CMAKE_REQUIRED_LIBRARIES "${OPENSSL_SSL_LIBRARY}" "${OPENSSL_CRYPTO_LIBRARY}")
endif()

check_cxx_source_compiles(
"
#include <openssl/ssl.h>
#if defined(OPENSSL_NO_NTLS)
# error ntls disabled
#endif
int main() {
SSL_CTX *ctx = SSL_CTX_new(NTLS_method());
if (ctx == nullptr) {
return 1;
}
SSL_CTX_enable_ntls(ctx);
SSL_CTX_free(ctx);
return 0;
}
"
THRIFT_HAVE_NTLS
)
endif()

# generate a config.h file
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/build/cmake/config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/thrift/config.h")

Expand Down
35 changes: 33 additions & 2 deletions build/cmake/DefineOptions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,33 @@ CMAKE_DEPENDENT_OPTION(BUILD_C_GLIB "Build C (GLib) library" ON

# OpenSSL
if(WITH_CPP OR WITH_C_GLIB)
find_package(OpenSSL)
option(WITH_TONGSUO "Build with Tongsuo instead of OpenSSL" OFF)
set(TONGSUO_ROOT_DIR "" CACHE PATH "Root directory of a Tongsuo installation")

if(WITH_TONGSUO)
find_package(Tongsuo REQUIRED)
set(OPENSSL_FOUND TRUE)
set(OPENSSL_INCLUDE_DIR "${TONGSUO_INCLUDE_DIR}")
set(OPENSSL_SSL_LIBRARY "${TONGSUO_SSL_LIBRARY}")
set(OPENSSL_CRYPTO_LIBRARY "${TONGSUO_CRYPTO_LIBRARY}")
set(OPENSSL_LIBRARIES "${TONGSUO_SSL_LIBRARY}" "${TONGSUO_CRYPTO_LIBRARY}")
if(NOT TARGET OpenSSL::SSL)
add_library(OpenSSL::SSL UNKNOWN IMPORTED)
set_target_properties(OpenSSL::SSL PROPERTIES
IMPORTED_LOCATION "${TONGSUO_SSL_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${TONGSUO_INCLUDE_DIR}"
)
endif()
if(NOT TARGET OpenSSL::Crypto)
add_library(OpenSSL::Crypto UNKNOWN IMPORTED)
set_target_properties(OpenSSL::Crypto PROPERTIES
IMPORTED_LOCATION "${TONGSUO_CRYPTO_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${TONGSUO_INCLUDE_DIR}"
)
endif()
else()
find_package(OpenSSL)
endif()
CMAKE_DEPENDENT_OPTION(WITH_OPENSSL "Build with OpenSSL support" ON
"OPENSSL_FOUND" OFF)
endif()
Expand Down Expand Up @@ -164,7 +190,12 @@ message(STATUS "Language libraries:")
message(STATUS)
message(STATUS " Build with OpenSSL: ${WITH_OPENSSL}")
if(WITH_OPENSSL)
message(STATUS " Version: ${OPENSSL_VERSION}")
if(WITH_TONGSUO)
message(STATUS " Backend: Tongsuo")
message(STATUS " Root: ${TONGSUO_ROOT_DIR}")
else()
message(STATUS " Version: ${OPENSSL_VERSION}")
endif()
endif()
message(STATUS)
message(STATUS " Build C++ library: ${BUILD_CPP}")
Expand Down
80 changes: 80 additions & 0 deletions build/cmake/FindTongsuo.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

# Find Tongsuo (OpenSSL-compatible TLS library)
#
# TONGSUO_INCLUDE_DIR, TONGSUO_SSL_LIBRARY, TONGSUO_CRYPTO_LIBRARY
# Tongsuo_FOUND

include(FindPackageHandleStandardArgs)

find_path(TONGSUO_INCLUDE_DIR
NAMES openssl/ssl.h
HINTS
${TONGSUO_ROOT_DIR}
ENV TONGSUO_ROOT
PATH_SUFFIXES include
)

find_library(TONGSUO_SSL_LIBRARY
NAMES ssl libssl
HINTS
${TONGSUO_ROOT_DIR}
ENV TONGSUO_ROOT
PATH_SUFFIXES lib lib64
)

find_library(TONGSUO_CRYPTO_LIBRARY
NAMES crypto libcrypto
HINTS
${TONGSUO_ROOT_DIR}
ENV TONGSUO_ROOT
PATH_SUFFIXES lib lib64
)

find_package_handle_standard_args(Tongsuo
REQUIRED_VARS
TONGSUO_INCLUDE_DIR
TONGSUO_SSL_LIBRARY
TONGSUO_CRYPTO_LIBRARY
)

if(TONGSUO_FOUND)
if(NOT TARGET Tongsuo::SSL)
add_library(Tongsuo::SSL UNKNOWN IMPORTED)
set_target_properties(Tongsuo::SSL PROPERTIES
IMPORTED_LOCATION "${TONGSUO_SSL_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${TONGSUO_INCLUDE_DIR}"
)
endif()

if(NOT TARGET Tongsuo::Crypto)
add_library(Tongsuo::Crypto UNKNOWN IMPORTED)
set_target_properties(Tongsuo::Crypto PROPERTIES
IMPORTED_LOCATION "${TONGSUO_CRYPTO_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${TONGSUO_INCLUDE_DIR}"
)
endif()
endif()

mark_as_advanced(
TONGSUO_INCLUDE_DIR
TONGSUO_SSL_LIBRARY
TONGSUO_CRYPTO_LIBRARY
)
3 changes: 3 additions & 0 deletions build/cmake/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,7 @@
/* Define to 1 if strerror_r returns char *. */
#cmakedefine STRERROR_R_CHAR_P 1

/* Define to 1 if NTLS support is available. */
#cmakedefine THRIFT_HAVE_NTLS 1

#endif
195 changes: 195 additions & 0 deletions lib/cpp/src/thrift/transport/TSSLSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,12 @@ static void buildErrors(string& message, int errno_copy = 0, int sslerrno = 0);
static bool matchName(const char* host, const char* pattern, int size);
static char uppercase(char c);

static void requireNtlsSupport() {
#ifndef THRIFT_HAVE_NTLS
throw TSSLException("NTLS is not available in this build");
#endif
}

// SSLContext implementation
SSLContext::SSLContext(const SSLProtocol& protocol) {
if (protocol == SSLTLS) {
Expand All @@ -192,6 +198,10 @@ SSLContext::SSLContext(const SSLProtocol& protocol) {
ctx_ = SSL_CTX_new(TLSv1_1_method());
} else if (protocol == TLSv1_2) {
ctx_ = SSL_CTX_new(TLSv1_2_method());
#ifdef THRIFT_HAVE_NTLS
} else if (protocol == NTLS) {
ctx_ = SSL_CTX_new(NTLS_method());
#endif
} else {
/// UNKNOWN PROTOCOL!
throw TSSLException("SSL_CTX_new: Unknown protocol");
Expand All @@ -202,6 +212,11 @@ SSLContext::SSLContext(const SSLProtocol& protocol) {
buildErrors(errors);
throw TSSLException("SSL_CTX_new: " + errors);
}
#ifdef THRIFT_HAVE_NTLS
if (protocol == NTLS) {
SSL_CTX_enable_ntls(ctx_);
}
#endif
SSL_CTX_set_mode(ctx_, SSL_MODE_AUTO_RETRY);

// Keep version-flexible negotiation for current protocol versions while setting
Expand Down Expand Up @@ -1092,6 +1107,186 @@ void TSSLSocketFactory::loadPrivateKeyFromBuffer(const char* aPrivateKey, const
}
}

void TSSLSocketFactory::loadSignCertificate(const char* path, const char* format) {
requireNtlsSupport();
if (path == nullptr || format == nullptr) {
throw TTransportException(TTransportException::BAD_ARGS,
"loadSignCertificate: either <path> or <format> is nullptr");
}
#ifdef THRIFT_HAVE_NTLS
if (strcmp(format, "PEM") == 0) {
if (SSL_CTX_use_sign_certificate_file(ctx_->get(), path, SSL_FILETYPE_PEM) == 0) {
int errno_copy = THRIFT_GET_SOCKET_ERROR;
string errors;
buildErrors(errors, errno_copy);
throw TSSLException("SSL_CTX_use_sign_certificate_file: " + errors);
}
} else {
throw TSSLException("Unsupported certificate format: " + string(format));
}
#endif
}

void TSSLSocketFactory::loadSignCertificateFromBuffer(const char* aCertificate, const char* format) {
requireNtlsSupport();
if (aCertificate == nullptr || format == nullptr) {
throw TTransportException(TTransportException::BAD_ARGS,
"loadSignCertificateFromBuffer: either <path> or <format> is nullptr");
}
#ifdef THRIFT_HAVE_NTLS
if (strcmp(format, "PEM") != 0) {
throw TSSLException("Unsupported certificate format: " + string(format));
}
BIO* mem = BIO_new(BIO_s_mem());
BIO_puts(mem, aCertificate);
X509* cert = PEM_read_bio_X509(mem, nullptr, nullptr, nullptr);
BIO_free(mem);
const int status = SSL_CTX_use_sign_certificate(ctx_->get(), cert);
X509_free(cert);
if (status != 1) {
int errno_copy = THRIFT_GET_SOCKET_ERROR;
string errors;
buildErrors(errors, errno_copy);
throw TSSLException("SSL_CTX_use_sign_certificate: " + errors);
}
#endif
}

void TSSLSocketFactory::loadSignPrivateKey(const char* path, const char* format) {
requireNtlsSupport();
if (path == nullptr || format == nullptr) {
throw TTransportException(TTransportException::BAD_ARGS,
"loadSignPrivateKey: either <path> or <format> is nullptr");
}
#ifdef THRIFT_HAVE_NTLS
if (strcmp(format, "PEM") == 0) {
if (SSL_CTX_use_sign_PrivateKey_file(ctx_->get(), path, SSL_FILETYPE_PEM) == 0) {
int errno_copy = THRIFT_GET_SOCKET_ERROR;
string errors;
buildErrors(errors, errno_copy);
throw TSSLException("SSL_CTX_use_sign_PrivateKey_file: " + errors);
}
} else {
throw TSSLException("Unsupported certificate format: " + string(format));
}
#endif
}

void TSSLSocketFactory::loadSignPrivateKeyFromBuffer(const char* aPrivateKey, const char* format) {
requireNtlsSupport();
if (aPrivateKey == nullptr || format == nullptr) {
throw TTransportException(TTransportException::BAD_ARGS,
"loadSignPrivateKeyFromBuffer: either <path> or <format> is nullptr");
}
#ifdef THRIFT_HAVE_NTLS
if (strcmp(format, "PEM") != 0) {
throw TSSLException("Unsupported certificate format: " + string(format));
}
BIO* mem = BIO_new(BIO_s_mem());
BIO_puts(mem, aPrivateKey);
EVP_PKEY* key = PEM_read_bio_PrivateKey(mem, nullptr, nullptr, nullptr);
BIO_free(mem);
const int status = SSL_CTX_use_sign_PrivateKey(ctx_->get(), key);
EVP_PKEY_free(key);
if (status == 0) {
int errno_copy = THRIFT_GET_SOCKET_ERROR;
string errors;
buildErrors(errors, errno_copy);
throw TSSLException("SSL_CTX_use_sign_PrivateKey: " + errors);
}
#endif
}

void TSSLSocketFactory::loadEncCertificate(const char* path, const char* format) {
requireNtlsSupport();
if (path == nullptr || format == nullptr) {
throw TTransportException(TTransportException::BAD_ARGS,
"loadEncCertificate: either <path> or <format> is nullptr");
}
#ifdef THRIFT_HAVE_NTLS
if (strcmp(format, "PEM") == 0) {
if (SSL_CTX_use_enc_certificate_file(ctx_->get(), path, SSL_FILETYPE_PEM) == 0) {
int errno_copy = THRIFT_GET_SOCKET_ERROR;
string errors;
buildErrors(errors, errno_copy);
throw TSSLException("SSL_CTX_use_enc_certificate_file: " + errors);
}
} else {
throw TSSLException("Unsupported certificate format: " + string(format));
}
#endif
}

void TSSLSocketFactory::loadEncCertificateFromBuffer(const char* aCertificate, const char* format) {
requireNtlsSupport();
if (aCertificate == nullptr || format == nullptr) {
throw TTransportException(TTransportException::BAD_ARGS,
"loadEncCertificateFromBuffer: either <path> or <format> is nullptr");
}
#ifdef THRIFT_HAVE_NTLS
if (strcmp(format, "PEM") != 0) {
throw TSSLException("Unsupported certificate format: " + string(format));
}
BIO* mem = BIO_new(BIO_s_mem());
BIO_puts(mem, aCertificate);
X509* cert = PEM_read_bio_X509(mem, nullptr, nullptr, nullptr);
BIO_free(mem);
const int status = SSL_CTX_use_enc_certificate(ctx_->get(), cert);
X509_free(cert);
if (status != 1) {
int errno_copy = THRIFT_GET_SOCKET_ERROR;
string errors;
buildErrors(errors, errno_copy);
throw TSSLException("SSL_CTX_use_enc_certificate: " + errors);
}
#endif
}

void TSSLSocketFactory::loadEncPrivateKey(const char* path, const char* format) {
requireNtlsSupport();
if (path == nullptr || format == nullptr) {
throw TTransportException(TTransportException::BAD_ARGS,
"loadEncPrivateKey: either <path> or <format> is nullptr");
}
#ifdef THRIFT_HAVE_NTLS
if (strcmp(format, "PEM") == 0) {
if (SSL_CTX_use_enc_PrivateKey_file(ctx_->get(), path, SSL_FILETYPE_PEM) == 0) {
int errno_copy = THRIFT_GET_SOCKET_ERROR;
string errors;
buildErrors(errors, errno_copy);
throw TSSLException("SSL_CTX_use_enc_PrivateKey_file: " + errors);
}
} else {
throw TSSLException("Unsupported certificate format: " + string(format));
}
#endif
}

void TSSLSocketFactory::loadEncPrivateKeyFromBuffer(const char* aPrivateKey, const char* format) {
requireNtlsSupport();
if (aPrivateKey == nullptr || format == nullptr) {
throw TTransportException(TTransportException::BAD_ARGS,
"loadEncPrivateKeyFromBuffer: either <path> or <format> is nullptr");
}
#ifdef THRIFT_HAVE_NTLS
if (strcmp(format, "PEM") != 0) {
throw TSSLException("Unsupported certificate format: " + string(format));
}
BIO* mem = BIO_new(BIO_s_mem());
BIO_puts(mem, aPrivateKey);
EVP_PKEY* key = PEM_read_bio_PrivateKey(mem, nullptr, nullptr, nullptr);
BIO_free(mem);
const int status = SSL_CTX_use_enc_PrivateKey(ctx_->get(), key);
EVP_PKEY_free(key);
if (status == 0) {
int errno_copy = THRIFT_GET_SOCKET_ERROR;
string errors;
buildErrors(errors, errno_copy);
throw TSSLException("SSL_CTX_use_enc_PrivateKey: " + errors);
}
#endif
}

void TSSLSocketFactory::loadTrustedCertificates(const char* path, const char* capath) {
if (path == nullptr) {
throw TTransportException(TTransportException::BAD_ARGS,
Expand Down
Loading
Loading