mirror of
https://github.com/savoirfairelinux/opendht.git
synced 2026-11-11 05:47:17 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63be084ab0 |
No files matched your search
+10
-9
@@ -1,13 +1,11 @@
|
||||
cmake_minimum_required (VERSION 3.1)
|
||||
project (opendht)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CMakeDependentOption)
|
||||
include(FindPkgConfig)
|
||||
include(cmake/CheckAtomic.cmake)
|
||||
|
||||
project (opendht)
|
||||
set (opendht_VERSION_MAJOR 2)
|
||||
set (opendht_VERSION_MINOR 1.9)
|
||||
set (opendht_VERSION_MINOR 1.6)
|
||||
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
|
||||
set (PACKAGE_VERSION ${opendht_VERSION})
|
||||
set (VERSION "${opendht_VERSION}")
|
||||
@@ -84,8 +82,8 @@ if (NOT MSVC)
|
||||
# https://cmake.org/cmake/help/latest/module/FindOpenSSL.html
|
||||
pkg_search_module(OPENSSL REQUIRED openssl)
|
||||
if (OPENSSL_FOUND)
|
||||
message(STATUS "Found OpenSSL ${OPENSSL_VERSION} ${OPENSSL_INCLUDE_DIRS}")
|
||||
include_directories(SYSTEM ${OPENSSL_INCLUDE_DIRS})
|
||||
message(STATUS "Found OpenSSL ${OPENSSL_VERSION}")
|
||||
include_directories(${OPENSSL_INCLUDE_DIRS})
|
||||
link_directories (${OPENSSL_LIBRARY_DIRS})
|
||||
else ()
|
||||
message(SEND_ERROR "OpenSSL is required for DHT proxy as specified")
|
||||
@@ -302,11 +300,9 @@ if (OPENDHT_HTTP)
|
||||
list (APPEND opendht_HEADERS
|
||||
include/opendht/proxy.h
|
||||
include/opendht/http.h
|
||||
src/compat/os_cert.h
|
||||
)
|
||||
list (APPEND opendht_SOURCES
|
||||
src/http.cpp
|
||||
src/compat/os_cert.cpp
|
||||
)
|
||||
endif ()
|
||||
|
||||
@@ -327,8 +323,13 @@ if(OPENDHT_ARGON2)
|
||||
include_directories(argon2/include/)
|
||||
endif()
|
||||
|
||||
# cross-platform compatibility sources
|
||||
set (COMPAT_DIR ${PROJECT_SOURCE_DIR}/src/compat/)
|
||||
list (APPEND opendht_SOURCES ${COMPAT_DIR}/os_cert.cpp)
|
||||
|
||||
if (MSVC)
|
||||
list (APPEND opendht_HEADERS src/compat/msvc/unistd.h)
|
||||
set (MSC_COMPAT_DIR ${COMPAT_DIR}/msvc/)
|
||||
list (APPEND opendht_SOURCES ${MSC_COMPAT_DIR}/unistd.h)
|
||||
endif ()
|
||||
|
||||
# Targets
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
# University of Illinois/NCSA
|
||||
# Open Source License
|
||||
#
|
||||
# Copyright (c) 2003-2017 University of Illinois at Urbana-Champaign.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Developed by:
|
||||
#
|
||||
# LLVM Team
|
||||
#
|
||||
# University of Illinois at Urbana-Champaign
|
||||
#
|
||||
# http://llvm.org
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal with
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
# of the Software, and to permit persons to whom the Software is furnished to do
|
||||
# so, subject to the following conditions:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimers.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimers in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# * Neither the names of the LLVM Team, University of Illinois at
|
||||
# Urbana-Champaign, nor the names of its contributors may be used to
|
||||
# endorse or promote products derived from this Software without specific
|
||||
# prior written permission.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
||||
# SOFTWARE.
|
||||
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(CheckLibraryExists)
|
||||
|
||||
# Sometimes linking against libatomic is required for atomic ops, if
|
||||
# the platform doesn't support lock-free atomics.
|
||||
|
||||
function(check_working_cxx_atomics varname)
|
||||
set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
|
||||
get_directory_property(compile_options COMPILE_OPTIONS)
|
||||
set(CMAKE_REQUIRED_FLAGS ${compile_options})
|
||||
CHECK_CXX_SOURCE_COMPILES("
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
int main() {
|
||||
struct Test { int64_t val; };
|
||||
std::atomic<Test> s;
|
||||
s.is_lock_free();
|
||||
}" ${varname})
|
||||
set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
|
||||
endfunction(check_working_cxx_atomics)
|
||||
|
||||
|
||||
if(NOT DEFINED PROXYGEN_COMPILER_IS_GCC_COMPATIBLE)
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE ON)
|
||||
elseif(MSVC)
|
||||
set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE OFF)
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE ON)
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel")
|
||||
set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# This isn't necessary on MSVC, so avoid command-line switch annoyance
|
||||
# by only running on GCC-like hosts.
|
||||
if(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE)
|
||||
# First check if atomics work without the library.
|
||||
check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB)
|
||||
# If not, check if the library exists, and atomics work with it.
|
||||
if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB)
|
||||
check_library_exists(atomic __atomic_fetch_add_4 "" HAVE_LIBATOMIC)
|
||||
if(HAVE_LIBATOMIC)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
|
||||
check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB)
|
||||
if (NOT HAVE_CXX_ATOMICS_WITH_LIB)
|
||||
message(FATAL_ERROR "Host compiler must support std::atomic!")
|
||||
endif()
|
||||
list(APPEND CMAKE_CXX_STANDARD_LIBRARIES -latomic)
|
||||
else()
|
||||
message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
dnl define macros
|
||||
m4_define([opendht_major_version], 2)
|
||||
m4_define([opendht_minor_version], 1)
|
||||
m4_define([opendht_patch_version], 9)
|
||||
m4_define([opendht_patch_version], 6)
|
||||
m4_define([opendht_version],
|
||||
[opendht_major_version.opendht_minor_version.opendht_patch_version])
|
||||
|
||||
|
||||
@@ -565,7 +565,7 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
* Return GnuTLS error code.
|
||||
* https://www.gnutls.org/manual/html_node/Error-codes.html
|
||||
*/
|
||||
std::pair<std::string, Blob> generateOcspRequest(gnutls_x509_crt_t& issuer);
|
||||
std::pair<Blob,Blob> generateOcspRequest(gnutls_x509_crt_t& issuer);
|
||||
|
||||
gnutls_x509_crt_t cert {nullptr};
|
||||
std::shared_ptr<Certificate> issuer {};
|
||||
|
||||
@@ -354,22 +354,6 @@ private:
|
||||
|
||||
OPENDHT_PUBLIC extern const HexMap hex_map;
|
||||
|
||||
inline std::string
|
||||
toHex(const uint8_t* data, size_t size) {
|
||||
std::string ret('\0', size * 2);
|
||||
for (size_t i=0; i<size; i++) {
|
||||
auto b = ret.data()+i*2;
|
||||
const auto& m = hex_map[data[i]];
|
||||
*((uint16_t*)b) = *((uint16_t*)&m);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline std::string
|
||||
toHex(const std::vector<uint8_t>& data) {
|
||||
return toHex(data.data(), data.size());
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
const char*
|
||||
Hash<N>::to_c_str() const
|
||||
|
||||
+2
-2
@@ -71,8 +71,8 @@ endif
|
||||
|
||||
libopendht_la_SOURCES += base64.h base64.cpp
|
||||
if PROXY_CLIENT_OR_SERVER
|
||||
libopendht_la_SOURCES += http.cpp compat/os_cert.cpp
|
||||
nobase_include_HEADERS += ../include/opendht/proxy.h ../include/opendht/http.h compat/os_cert.h
|
||||
libopendht_la_SOURCES += http.cpp
|
||||
nobase_include_HEADERS += ../include/opendht/proxy.h ../include/opendht/http.h
|
||||
endif
|
||||
|
||||
if ENABLE_PEER_DISCOVERY
|
||||
|
||||
+38
-15
@@ -27,20 +27,34 @@
|
||||
#endif
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#ifdef TARGET_OS_OSX
|
||||
#ifdef __APPLE__
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <Security/Security.h>
|
||||
#endif /*TARGET_OS_OSX*/
|
||||
#endif /*__APPLE__*/
|
||||
|
||||
#if EMBEDDED_ASN1_TIME_PARSE
|
||||
#ifdef _WIN32
|
||||
#undef X509_NAME
|
||||
#undef OCSP_REQUEST
|
||||
#undef OCSP_RESPONSE
|
||||
#define GENTIME_LENGTH 15
|
||||
#define UTCTIME_LENGTH 13
|
||||
#define ATOI2(ar) ((ar) += 2, ((ar)[-2] - '0') * 10 + ((ar)[-1] - '0'))
|
||||
extern "C" {
|
||||
// Taken from libressl/src/crypto/asn1/a_time_tm.c
|
||||
/*
|
||||
* Parse an RFC 5280 format ASN.1 time string.
|
||||
*
|
||||
* mode must be:
|
||||
* 0 if we expect to parse a time as specified in RFC 5280 for an X509 object.
|
||||
* V_ASN1_UTCTIME if we wish to parse an RFC5280 format UTC time.
|
||||
* V_ASN1_GENERALIZEDTIME if we wish to parse an RFC5280 format Generalized time.
|
||||
*
|
||||
* Returns:
|
||||
* -1 if the string was invalid.
|
||||
* V_ASN1_UTCTIME if the string validated as a UTC time string.
|
||||
* V_ASN1_GENERALIZEDTIME if the string validated as a Generalized time string.
|
||||
*
|
||||
* Fills in *tm with the corresponding time if tm is non NULL.
|
||||
*/
|
||||
int
|
||||
ASN1_time_parse(const char* bytes, size_t len, struct tm* tm, int mode)
|
||||
{
|
||||
@@ -117,10 +131,9 @@ ASN1_time_parse(const char* bytes, size_t len, struct tm* tm, int mode)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return type;
|
||||
return (type);
|
||||
}
|
||||
}
|
||||
#endif /* EMBEDDED_ASN1_TIME_PARSE */
|
||||
#endif /*_WIN32*/
|
||||
|
||||
namespace dht {
|
||||
namespace http {
|
||||
@@ -128,6 +141,7 @@ namespace http {
|
||||
PEMCache::PEMCache(const std::shared_ptr<Logger>& l)
|
||||
: logger(l)
|
||||
{
|
||||
X509* x509cert;
|
||||
#ifdef _WIN32
|
||||
PCCERT_CONTEXT pContext = NULL;
|
||||
HCERTSTORE hSystemStore;
|
||||
@@ -138,13 +152,14 @@ PEMCache::PEMCache(const std::shared_ptr<Logger>& l)
|
||||
return;
|
||||
}
|
||||
while (pContext = CertEnumCertificatesInStore(hSystemStore, pContext)) {
|
||||
x509cert = nullptr;
|
||||
const uint8_t* encoded_cert = pContext->pbCertEncoded;
|
||||
X509Ptr x509cert(d2i_X509(nullptr, &encoded_cert, pContext->cbCertEncoded), &X509_free);
|
||||
x509cert = d2i_X509(nullptr, &encoded_cert, pContext->cbCertEncoded);
|
||||
if (x509cert)
|
||||
pems_.emplace_back(std::move(x509cert));
|
||||
pems_.push_back(x509cert);
|
||||
}
|
||||
CertCloseStore(hSystemStore, 0);
|
||||
#elif TARGET_OS_OSX
|
||||
#elif __APPLE__
|
||||
CFArrayRef result = NULL;
|
||||
OSStatus osStatus;
|
||||
|
||||
@@ -162,6 +177,7 @@ PEMCache::PEMCache(const std::shared_ptr<Logger>& l)
|
||||
}
|
||||
CFDataRef rawData = NULL;
|
||||
for (CFIndex i = 0; i < CFArrayGetCount(result); i++) {
|
||||
x509cert = nullptr;
|
||||
SecCertificateRef cert = (SecCertificateRef) CFArrayGetValueAtIndex(result, i);
|
||||
rawData = SecCertificateCopyData(cert);
|
||||
if (!rawData) {
|
||||
@@ -170,9 +186,9 @@ PEMCache::PEMCache(const std::shared_ptr<Logger>& l)
|
||||
break;
|
||||
}
|
||||
const uint8_t* rawDataPtr = CFDataGetBytePtr(rawData);
|
||||
X509Ptr x509cert(d2i_X509(nullptr, &rawDataPtr, CFDataGetLength(rawData)), &X509_free);
|
||||
x509cert = d2i_X509(nullptr, &rawDataPtr, CFDataGetLength(rawData));
|
||||
if (x509cert)
|
||||
pems_.emplace_back(std::move(x509cert));
|
||||
pems_.push_back(x509cert);
|
||||
CFRelease(rawData);
|
||||
rawData = NULL;
|
||||
}
|
||||
@@ -182,7 +198,14 @@ PEMCache::PEMCache(const std::shared_ptr<Logger>& l)
|
||||
if (rawData != NULL) {
|
||||
CFRelease(rawData);
|
||||
}
|
||||
#endif /*TARGET_OS_OSX, _WIN32*/
|
||||
#endif /*__APPLE__, _WIN32*/
|
||||
}
|
||||
|
||||
PEMCache::~PEMCache()
|
||||
{
|
||||
for (const auto pem : pems_)
|
||||
if (pem)
|
||||
X509_free(pem);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -196,8 +219,8 @@ PEMCache::fillX509Store(SSL_CTX* ctx)
|
||||
logger->e("couldn't get the context cert store");
|
||||
return;
|
||||
}
|
||||
for (const auto& pem : pems_) {
|
||||
if (X509_STORE_add_cert(store, pem.get()) == 1)
|
||||
for (const auto pem : pems_) {
|
||||
if (X509_STORE_add_cert(store, pem) == 1)
|
||||
continue;
|
||||
if (logger)
|
||||
logger->d("couldn't add local certificate");
|
||||
|
||||
+8
-31
@@ -24,35 +24,13 @@
|
||||
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#if (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER > 0x20501000L))
|
||||
#define EMBEDDED_ASN1_TIME_PARSE 0
|
||||
#else
|
||||
#define EMBEDDED_ASN1_TIME_PARSE 1
|
||||
#endif
|
||||
|
||||
#if EMBEDDED_ASN1_TIME_PARSE
|
||||
#ifdef _WIN32
|
||||
#include <crypto/x509.h> // to expose x509_store_ctx_st
|
||||
#define V_ASN1_UTCTIME 23
|
||||
#define V_ASN1_GENERALIZEDTIME 24
|
||||
|
||||
extern "C" {
|
||||
/*
|
||||
* Parse an RFC 5280 format ASN.1 time string.
|
||||
*
|
||||
* mode must be:
|
||||
* 0 if we expect to parse a time as specified in RFC 5280 for an X509 object.
|
||||
* V_ASN1_UTCTIME if we wish to parse an RFC5280 format UTC time.
|
||||
* V_ASN1_GENERALIZEDTIME if we wish to parse an RFC5280 format Generalized time.
|
||||
*
|
||||
* Returns:
|
||||
* -1 if the string was invalid.
|
||||
* V_ASN1_UTCTIME if the string validated as a UTC time string.
|
||||
* V_ASN1_GENERALIZEDTIME if the string validated as a Generalized time string.
|
||||
*
|
||||
* Fills in *tm with the corresponding time if tm is non NULL.
|
||||
*/
|
||||
#define timegm _mkgmtime
|
||||
int ASN1_time_parse(const char* bytes, size_t len, struct tm* tm, int mode);
|
||||
}
|
||||
#endif
|
||||
#endif /*_WIN32*/
|
||||
|
||||
namespace dht {
|
||||
namespace http {
|
||||
@@ -63,16 +41,15 @@ namespace http {
|
||||
class PEMCache
|
||||
{
|
||||
PEMCache(const std::shared_ptr<Logger>& l);
|
||||
|
||||
using X509Ptr = std::unique_ptr<X509, void(*)(X509*)>;
|
||||
std::vector<X509Ptr> pems_;
|
||||
~PEMCache();
|
||||
std::vector<X509*> pems_;
|
||||
std::shared_ptr<Logger> logger;
|
||||
|
||||
public:
|
||||
static PEMCache& instance(const std::shared_ptr<Logger>& l)
|
||||
{
|
||||
static PEMCache instance_(l);
|
||||
return instance_;
|
||||
static PEMCache* instance_ = new PEMCache(l);
|
||||
return *instance_;
|
||||
}
|
||||
|
||||
void fillX509Store(SSL_CTX* ctx);
|
||||
|
||||
+68
-45
@@ -1034,7 +1034,7 @@ Certificate::getPreferredDigest() const
|
||||
return getPublicKey().getPreferredDigest();
|
||||
}
|
||||
|
||||
std::pair<std::string, Blob>
|
||||
std::pair<Blob,Blob>
|
||||
Certificate::generateOcspRequest(gnutls_x509_crt_t& issuer)
|
||||
{
|
||||
gnutls_ocsp_req_t rreq;
|
||||
@@ -1055,9 +1055,9 @@ Certificate::generateOcspRequest(gnutls_x509_crt_t& issuer)
|
||||
err = gnutls_ocsp_req_export(req.get(), &rdata);
|
||||
if (err != 0)
|
||||
throw CryptoException(gnutls_strerror(err));
|
||||
std::string ret((char*)rdata.data, (char*)rdata.data + rdata.size);
|
||||
Blob ret(rdata.data, rdata.data + rdata.size);
|
||||
gnutls_free(rdata.data);
|
||||
return std::make_pair<std::string, Blob>(std::move(ret), std::move(noncebuf));
|
||||
return std::make_pair<Blob,Blob>(std::move(ret), std::move(noncebuf));
|
||||
}
|
||||
|
||||
// PrivateKey
|
||||
@@ -1162,11 +1162,13 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden
|
||||
Certificate ret {cert};
|
||||
|
||||
setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60);
|
||||
if (int err = gnutls_x509_crt_set_key(cert, key.x509_key)) {
|
||||
throw CryptoException(std::string("Error when setting certificate key ") + gnutls_strerror(err));
|
||||
if (gnutls_x509_crt_set_key(cert, key.x509_key) != GNUTLS_E_SUCCESS) {
|
||||
std::cerr << "Error when setting certificate key" << std::endl;
|
||||
return {};
|
||||
}
|
||||
if (int err = gnutls_x509_crt_set_version(cert, 3)) {
|
||||
throw CryptoException(std::string("Error when setting certificate version ") + gnutls_strerror(err));
|
||||
if (gnutls_x509_crt_set_version(cert, 3) != GNUTLS_E_SUCCESS) {
|
||||
std::cerr << "Error when setting certificate version" << std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
// TODO: compute the subject key using the recommended RFC method
|
||||
@@ -1191,15 +1193,18 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden
|
||||
|
||||
if (ca.first && ca.second) {
|
||||
if (not ca.second->isCA()) {
|
||||
throw CryptoException("Signing certificate must be CA");
|
||||
// Signing certificate must be CA.
|
||||
return {};
|
||||
}
|
||||
if (int err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, pk.getPreferredDigest(), 0)) {
|
||||
throw CryptoException(std::string("Error when signing certificate ") + gnutls_strerror(err));
|
||||
if (gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, pk.getPreferredDigest(), 0) != GNUTLS_E_SUCCESS) {
|
||||
std::cerr << "Error when signing certificate" << std::endl;
|
||||
return {};
|
||||
}
|
||||
ret.issuer = ca.second;
|
||||
} else {
|
||||
if (int err = gnutls_x509_crt_privkey_sign(cert, cert, key.key, pk.getPreferredDigest(), 0)) {
|
||||
throw CryptoException(std::string("Error when signing certificate ") + gnutls_strerror(err));
|
||||
if (gnutls_x509_crt_privkey_sign(cert, cert, key.key, pk.getPreferredDigest(), 0) != GNUTLS_E_SUCCESS) {
|
||||
std::cerr << "Error when signing certificate" << std::endl;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1301,47 +1306,65 @@ OcspResponse::getCertificateStatus() const
|
||||
gnutls_ocsp_verify_reason_t
|
||||
OcspResponse::verifyDirect(const Certificate& crt, const Blob& nonce)
|
||||
{
|
||||
// Check OCSP response
|
||||
int ret = gnutls_ocsp_resp_get_status(response);
|
||||
if (ret < 0)
|
||||
throw CryptoException(gnutls_strerror(ret));
|
||||
gnutls_ocsp_resp_status_t status = (gnutls_ocsp_resp_status_t)ret;
|
||||
if (status != GNUTLS_OCSP_RESP_SUCCESSFUL)
|
||||
throw CryptoException("OCSP request unsuccessful: " + std::to_string(ret));
|
||||
|
||||
// Check whether the OCSP response is about the provided certificate.
|
||||
if ((ret = gnutls_ocsp_resp_check_crt(response, 0, crt.cert)) < 0)
|
||||
throw CryptoException(gnutls_strerror(ret));
|
||||
|
||||
// Verify signature of the Basic OCSP response against the public key in the issuer certificate.
|
||||
// https://www.gnutls.org/manual/html_node/Error-codes.html
|
||||
int ret = -1;
|
||||
// http://www.gnu.org/software/gnutls/reference/gnutls-ocsp.html#gnutls-ocsp-verify-reason-t
|
||||
unsigned int verify = 0;
|
||||
ret = gnutls_ocsp_resp_verify_direct(response, crt.issuer->cert, &verify, 0);
|
||||
if (ret < 0)
|
||||
throw CryptoException(gnutls_strerror(ret));
|
||||
// http://www.gnu.org/software/gnutls/reference/gnutls-ocsp.html#gnutls-ocsp-cert-status-t
|
||||
unsigned int status = 6; // by default assume GNUTLS_OCSP_RESP_UNAUTHORIZED
|
||||
|
||||
// Check certificate revocation status
|
||||
unsigned status_ocsp;
|
||||
ret = gnutls_ocsp_resp_get_single(response, 0, NULL, NULL, NULL, NULL, &status_ocsp, NULL, NULL, NULL, NULL);
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030103
|
||||
/*
|
||||
* This function will check whether the OCSP response is about the provided certificate.
|
||||
* index: Specifies response number to get. Use (0) to get the first one.
|
||||
*/
|
||||
if ((ret = gnutls_ocsp_resp_check_crt(response, 0, crt.cert)) < 0)
|
||||
goto end;
|
||||
#endif
|
||||
/*
|
||||
* Verify signature of the Basic OCSP Response against the public key in the issuer certificate.
|
||||
* http://www.gnu.org/software/gnutls/reference/gnutls-ocsp.html#gnutls-ocsp-resp-verify-direct
|
||||
*/
|
||||
ret = gnutls_ocsp_resp_verify_direct(response, crt.issuer->cert /*signer*/, &verify, 0);
|
||||
if (ret < 0)
|
||||
throw CryptoException(gnutls_strerror(ret));
|
||||
gnutls_ocsp_cert_status_t certStatus = (gnutls_ocsp_cert_status_t)ret;
|
||||
if (certStatus == GNUTLS_OCSP_CERT_REVOKED)
|
||||
throw CryptoException("Certificate was revoked");
|
||||
else if (certStatus != GNUTLS_OCSP_CERT_GOOD)
|
||||
throw CryptoException("Certificate is unknown");
|
||||
|
||||
// Ensure no replay attack has been done
|
||||
goto end;
|
||||
ret = gnutls_ocsp_resp_check_crt(response, 0 /*index*/, crt.cert);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
/*
|
||||
* This function will return the certificate information of the indx'ed response in the
|
||||
* Basic OCSP Response resp. The information returned corresponds to the OCSP SingleResponse
|
||||
* structure except the final singleExtensions.
|
||||
* http://www.gnu.org/software/gnutls/reference/gnutls-ocsp.html#gnutls-ocsp-resp-get-single
|
||||
*/
|
||||
ret = gnutls_ocsp_resp_get_single(response, 0, NULL, NULL, NULL, NULL, &status, NULL, NULL, NULL, NULL);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
gnutls_datum_t rnonce;
|
||||
/*
|
||||
* This function will return the Basic OCSP Response nonce extension data.
|
||||
*/
|
||||
ret = gnutls_ocsp_resp_get_nonce(response, NULL, &rnonce);
|
||||
if (ret < 0)
|
||||
throw CryptoException(gnutls_strerror(ret));
|
||||
goto end;
|
||||
// Ensure no replay attack has been done
|
||||
if (rnonce.size != nonce.size() || memcmp(nonce.data(), rnonce.data, nonce.size()) != 0){
|
||||
gnutls_free(rnonce.data);
|
||||
throw CryptoException(gnutls_strerror(GNUTLS_E_OCSP_RESPONSE_ERROR));
|
||||
ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
|
||||
goto end;
|
||||
}
|
||||
gnutls_free(rnonce.data);
|
||||
|
||||
return (gnutls_ocsp_verify_reason_t) verify;
|
||||
end:
|
||||
/*
|
||||
* OCSP validation outcome based on interogative aspects
|
||||
*/
|
||||
if (ret != GNUTLS_E_SUCCESS)
|
||||
throw CryptoException(gnutls_strerror(ret));
|
||||
else if (status != GNUTLS_OCSP_CERT_GOOD)
|
||||
if (status == GNUTLS_OCSP_CERT_REVOKED)
|
||||
throw CryptoException("Certificate was revoked");
|
||||
else
|
||||
throw CryptoException("Certificate is unknown");
|
||||
else
|
||||
return (gnutls_ocsp_verify_reason_t) verify;
|
||||
}
|
||||
|
||||
// RevocationList
|
||||
|
||||
+23
-45
@@ -31,14 +31,10 @@
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509_vfy.h>
|
||||
|
||||
#define MAXAGE_SEC (14*24*60*60)
|
||||
#define JITTER_SEC (60)
|
||||
#define OCSP_MAX_RESPONSE_SIZE (20480)
|
||||
#ifdef _WIN32
|
||||
#define timegm _mkgmtime
|
||||
#endif
|
||||
|
||||
namespace dht {
|
||||
namespace http {
|
||||
@@ -103,41 +99,19 @@ Url::toString() const
|
||||
|
||||
std::atomic_uint Connection::ids_ {1};
|
||||
|
||||
std::shared_ptr<asio::ssl::context>
|
||||
newTlsClientContext(const std::shared_ptr<dht::Logger>& logger)
|
||||
{
|
||||
auto ctx = std::make_shared<asio::ssl::context>(asio::ssl::context::tls_client);
|
||||
ctx->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert);
|
||||
|
||||
if (char* path = getenv("CA_ROOT_FILE")) {
|
||||
if (logger)
|
||||
logger->d("Using CA file: %s", path);
|
||||
ctx->load_verify_file(path);
|
||||
} else if (char* path = getenv("CA_ROOT_PATH")) {
|
||||
if (logger)
|
||||
logger->d("Using CA path: %s", path);
|
||||
ctx->add_verify_path(path);
|
||||
} else {
|
||||
#ifdef __ANDROID__
|
||||
if (logger)
|
||||
logger->d("Using CA path: /system/etc/security/cacerts");
|
||||
ctx->add_verify_path("/system/etc/security/cacerts");
|
||||
#elif defined(WIN32) || defined(TARGET_OS_OSX)
|
||||
PEMCache::instance(logger).fillX509Store(ctx->native_handle());
|
||||
#else
|
||||
if (logger)
|
||||
logger->d("Using default CA path");
|
||||
ctx->set_default_verify_paths();
|
||||
#endif
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
Connection::Connection(asio::io_context& ctx, const bool ssl, std::shared_ptr<dht::Logger> l)
|
||||
: id_(Connection::ids_++), ctx_(ctx), istream_(&read_buf_), logger_(l)
|
||||
{
|
||||
if (ssl) {
|
||||
ssl_ctx_ = newTlsClientContext(l);
|
||||
ssl_ctx_ = std::make_shared<asio::ssl::context>(asio::ssl::context::tls_client);
|
||||
ssl_ctx_->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert);
|
||||
#ifdef __ANDROID__
|
||||
ssl_ctx_->add_verify_path("/system/etc/security/cacerts");
|
||||
#elif defined(WIN32) || defined(__APPLE__)
|
||||
PEMCache::instance(l).fillX509Store(ssl_ctx_->native_handle());
|
||||
#else
|
||||
ssl_ctx_->set_default_verify_paths();
|
||||
#endif
|
||||
ssl_socket_ = std::make_unique<ssl_socket_t>(ctx_, ssl_ctx_);
|
||||
if (logger_)
|
||||
logger_->d("[connection:%i] start https session", id_);
|
||||
@@ -153,18 +127,23 @@ Connection::Connection(asio::io_context& ctx, std::shared_ptr<dht::crypto::Certi
|
||||
const dht::crypto::Identity& identity, std::shared_ptr<dht::Logger> l)
|
||||
: id_(Connection::ids_++), ctx_(ctx), istream_(&read_buf_), logger_(l)
|
||||
{
|
||||
ssl_ctx_ = std::make_shared<asio::ssl::context>(asio::ssl::context::tls_client);
|
||||
ssl_ctx_->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert);
|
||||
#ifdef __ANDROID__
|
||||
ssl_ctx_->add_verify_path("/system/etc/security/cacerts");
|
||||
#elif WIN32 || defined(__APPLE__)
|
||||
PEMCache::instance(l).fillX509Store(ssl_ctx_->native_handle());
|
||||
#else
|
||||
ssl_ctx_->set_default_verify_paths();
|
||||
#endif
|
||||
asio::error_code ec;
|
||||
if (server_ca) {
|
||||
ssl_ctx_ = std::make_shared<asio::ssl::context>(asio::ssl::context::tls_client);
|
||||
ssl_ctx_->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert);
|
||||
if (server_ca){
|
||||
auto ca = server_ca->toString(false/*chain*/);
|
||||
ssl_ctx_->add_certificate_authority(asio::const_buffer{ca.data(), ca.size()}, ec);
|
||||
if (ec)
|
||||
throw std::runtime_error("Error adding certificate authority: " + ec.message());
|
||||
else if (logger_)
|
||||
logger_->d("[connection:%i] certficate authority %s", id_, server_ca->getUID().c_str());
|
||||
} else {
|
||||
ssl_ctx_ = newTlsClientContext(l);
|
||||
}
|
||||
if (identity.first){
|
||||
auto key = identity.first->serialize();
|
||||
@@ -258,7 +237,7 @@ issuer_from_chain(STACK_OF(X509)* fullchain)
|
||||
using OscpRequestPtr = std::unique_ptr<OCSP_REQUEST, decltype(&OCSP_REQUEST_free)>;
|
||||
struct OscpRequestInfo {
|
||||
OscpRequestPtr req {nullptr, &OCSP_REQUEST_free};
|
||||
std::string data;
|
||||
std::vector<uint8_t> data;
|
||||
std::string url;
|
||||
};
|
||||
|
||||
@@ -328,7 +307,7 @@ ocspRequestFromCert(STACK_OF(X509)* fullchain, const std::shared_ptr<Logger>& lo
|
||||
logger->e("Unable to allocte memory");
|
||||
return {};
|
||||
}
|
||||
request->data = std::string((char*)data, (char*)data+size);
|
||||
request->data = std::vector<uint8_t>(data, data+size);
|
||||
free(data);
|
||||
return request;
|
||||
}
|
||||
@@ -500,15 +479,14 @@ Connection::set_ssl_verification(const std::string& hostname, const asio::ssl::v
|
||||
asio::io_context io_ctx;
|
||||
auto ocspReq = std::make_shared<Request>(io_ctx, ocspInfo->url, [&](const Response& ocspResp){
|
||||
if (ocspResp.status_code == 200) {
|
||||
ocspVerified = ocspValidateResponse(*ocspInfo, chain, ocspResp.body, X509_STORE_CTX_get0_store(ctx.native_handle()), logger);
|
||||
ocspVerified = ocspValidateResponse(*ocspInfo, chain, ocspResp.body, ctx.native_handle()->ctx, logger);
|
||||
} else {
|
||||
if (logger)
|
||||
logger->w("[http::connection:%i] TLS OCSP check error", id);
|
||||
}
|
||||
}, logger);
|
||||
ocspReq->set_method(restinio::http_method_post());
|
||||
ocspReq->set_header_field(restinio::http_field_t::content_type, "application/ocsp-request");
|
||||
ocspReq->set_body(ocspInfo->data);
|
||||
ocspReq->set_body({ocspInfo->data.begin(), ocspInfo->data.end()});
|
||||
ocspReq->send();
|
||||
io_ctx.run();
|
||||
if (not ocspVerified)
|
||||
|
||||
+6
-7
@@ -39,10 +39,8 @@ public:
|
||||
}
|
||||
|
||||
static ValueCallback cacheCallback(ValueCallback&& cb, std::function<void()>&& onCancel) {
|
||||
return [
|
||||
cache = std::make_shared<OpValueCache>(std::forward<ValueCallback>(cb)),
|
||||
onCancel = std::move(onCancel)
|
||||
](const std::vector<Sp<Value>>& vals, bool expired){
|
||||
auto cache = std::make_shared<OpValueCache>(std::forward<ValueCallback>(cb));
|
||||
return [cache, onCancel](const std::vector<Sp<Value>>& vals, bool expired){
|
||||
auto ret = cache->onValue(vals, expired);
|
||||
if (not ret)
|
||||
onCancel();
|
||||
@@ -51,9 +49,10 @@ public:
|
||||
}
|
||||
|
||||
bool onValue(const std::vector<Sp<Value>>& vals, bool expired, const system_clock::time_point& t = system_clock::time_point::min()) {
|
||||
return expired
|
||||
? onValuesExpired(vals, t)
|
||||
: onValuesAdded(vals, t);
|
||||
if (expired)
|
||||
return onValuesExpired(vals, t);
|
||||
else
|
||||
return onValuesAdded(vals, t);
|
||||
}
|
||||
|
||||
bool onValuesAdded(const std::vector<Sp<Value>>& vals, const system_clock::time_point& t = system_clock::time_point::min());
|
||||
|
||||
+4
-1
@@ -76,7 +76,10 @@ std::ostream& operator<< (std::ostream& s, const Value& v)
|
||||
s.write((const char*)v.data.data(), v.data.size());
|
||||
s << '"';
|
||||
} else if (v.data.size() < 1024) {
|
||||
s << toHex(v.data.data(), v.data.size());
|
||||
s << std::hex;
|
||||
for (auto i : v.data)
|
||||
s << std::setfill('0') << std::setw(2) << (unsigned)i;
|
||||
s << std::dec;
|
||||
} else {
|
||||
s << v.data.size() << " bytes";
|
||||
}
|
||||
|
||||
+3
-2
@@ -192,10 +192,11 @@ private:
|
||||
auto v = values.find(vid);
|
||||
if (v == values.end())
|
||||
return {};
|
||||
std::vector<Sp<Value>> val {std::move(v->second.data)};
|
||||
const std::vector<Sp<Value>> val {std::move(v->second.data)};
|
||||
values.erase(v);
|
||||
auto cb = callback;
|
||||
CallbackQueue ret;
|
||||
ret.emplace_back([cb = callback, val = std::move(val)]{
|
||||
ret.emplace_back([cb, val]{
|
||||
if (cb) cb(val, true);
|
||||
});
|
||||
return ret;
|
||||
|
||||
@@ -1,44 +1,14 @@
|
||||
[Unit]
|
||||
Description=OpenDHT standalone node
|
||||
Documentation=man:dhtnode(1)
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=opendht
|
||||
Group=opendht
|
||||
ExecStart=@bindir@/dhtnode -s $DHT_ARGS
|
||||
Restart=on-failure
|
||||
RestartSec=2s
|
||||
LimitNOFILE=65536
|
||||
DynamicUser=yes
|
||||
EnvironmentFile=@sysconfdir@/dhtnode.conf
|
||||
ExecStart=@bindir@/dhtnode -s $DHT_ARGS
|
||||
KillMode=process
|
||||
WorkingDirectory=/tmp
|
||||
|
||||
# Hardening
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
LockPersonality=yes
|
||||
NoNewPrivileges=yes
|
||||
PrivateDevices=yes
|
||||
PrivateTmp=yes
|
||||
PrivateUsers=yes
|
||||
ProtectClock=yes
|
||||
ProtectControlGroups=yes
|
||||
ProtectHome=yes
|
||||
ProtectHostname=yes
|
||||
ProtectKernelLogs=yes
|
||||
ProtectKernelModules=yes
|
||||
ProtectKernelTunables=yes
|
||||
ProtectSystem=strict
|
||||
ReadOnlyDirectories=/
|
||||
ReadWriteDirectories=-/proc/self
|
||||
ReadWriteDirectories=-/var/run
|
||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
||||
RestrictNamespaces=yes
|
||||
RestrictRealtime=yes
|
||||
SystemCallArchitectures=native
|
||||
SystemCallFilter=@system-service
|
||||
Restart=on-failure
|
||||
Type=simple
|
||||
DynamicUser=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in new issue
Block a user