Compare commits

...
Author SHA1 Message Date
Adrien Béraud df85abfabe cmake: use THREADS_PREFER_PTHREAD_FLAG 2020-12-30 10:32:27 -05:00
Bruno Pagani e6c760ec6b Fix use of OPENDHT_SYSTEMD_UNIT_FILE_LOCATION
For some reason 1778f64048 reverted part of 4d70c214b0

This commit fixes that.
2020-12-22 18:03:31 -05:00
Adrien Béraud a77dc855f0 OCSP: use RFC-mandated parameters
* use 32 bytes nounce
* use SHA-1 for the certificate ID
2020-12-17 12:35:33 -05:00
Adrien Béraud 2524e167d9 tests: add test for toHex 2020-12-08 14:39:25 -05:00
Adrien Béraud 638d1c91f1 toHex: use proper std::string constructor 2020-12-08 14:34:33 -05:00
Amin Bandali ba4058dfd9 cmake: fix atomic check, hopefully 2020-12-04 16:55:03 -05:00
Adrien Béraud ab90a170af http: checkOcsp is void 2020-11-24 16:16:11 -05:00
Adrien Béraud f780499241 ocsp response: add string constructor 2020-11-24 16:11:02 -05:00
Adrien Béraud 91709bc999 proxytester: disable https for now 2020-11-24 15:59:42 -05:00
Adrien Béraud 72725dc5c1 http: make OCSP check optional 2020-11-24 15:34:19 -05:00
Adrien Béraud 3098439db2 proxy client: set CA for every request 2020-11-24 15:22:14 -05:00
Adrien Béraud 6441a09e09 ocsp: fix memleaks 2020-11-20 14:42:55 -05:00
Adrien Béraud 57e7699723 update to version 2.1.9 2020-11-20 11:39:01 -05:00
Adrien Béraud 17e1cfbbbe crypto: export OCSP request as string 2020-11-20 11:38:11 -05:00
Adrien Béraud bfe1311ca8 crypto: cleanup OCSP result check 2020-11-19 17:12:54 -05:00
Adrien Béraud 537a1650f2 infohash: add toHex(const std::string&) 2020-11-19 17:07:06 -05:00
Kateryna Kostiuk 8c852c20e7 os_cert: do not load for iOS 2020-11-18 15:47:10 -05:00
Adrien Béraud 1da46382d3 cmake: add missing include in CheckAtomic 2020-11-17 16:30:36 -05:00
Adrien Béraud 4953888af3 update to version 2.1.8 2020-11-17 16:24:30 -05:00
Adrien Béraud 22de868c6c cmake: check for 64 bits atomic support 2020-11-17 16:23:43 -05:00
Adrien Béraud 0998707e03 automake: add os_cert 2020-11-17 15:48:13 -05:00
Adrien Béraud b5fcd49b7b os_cert: only build with http 2020-11-17 15:20:46 -05:00
Adrien Béraud 81cdd9650b os_cert: cleanup 2020-11-17 14:37:03 -05:00
Adrien Béraud e028cea687 os_cert: only define timegm on Windows 2020-11-17 13:15:22 -05:00
Adrien Béraud 17ed4a9e26 os_cert: include crypto/x509 from OpenSSL 3.0 2020-11-17 12:27:41 -05:00
Adrien Béraud 3ff318b9e4 os_cert: cleanup detection of ASN1_time_parse 2020-11-17 11:35:07 -05:00
Adrien Béraud 0c11c25c66 infohash: make toHex inline 2020-11-17 11:34:40 -05:00
Adrien Béraud 0d31139402 crypto: throw in case of certificate generation error 2020-11-16 17:35:00 -05:00
Adrien Béraud e970cac4d7 infohash: expose toHex 2020-11-16 14:58:35 -05:00
Adrien Béraud 7c8eecd745 update to version 2.1.7 2020-11-15 17:25:12 -05:00
Adrien Béraud 4d87c2267b os_cert: build ASN1_time_parse if not libressl 2020-11-15 00:42:29 -05:00
Adrien Béraud 88b2439deb http: use string for body, fix log arguments 2020-11-14 18:07:05 -05:00
Federico Ceratto 766a06c69a Remove line 2020-11-13 09:33:11 -05:00
Federico Ceratto aa502553bb Put @bindir@ back 2020-11-13 09:33:11 -05:00
Federico Ceratto 05ff4205d2 Configure dhtnode service sandboxing
Tested on Debian Sid
2020-11-13 09:33:11 -05:00
Adrien Béraud 9d937bb277 http: factor setting CA source 2020-11-12 19:00:02 -05:00
Andreas Traczyk 1621515b3c http: use local cache to store pre-decoded certs
- pre-decode certs from DER->PEM and store them so http connections
  can add them the ssl context x509 store
- fixes the windows build by adding the crypto/x509 header
2020-11-12 18:58:18 -05:00
Adrien Béraud 30261e70ad cache: cleanup, small perf improvements 2020-11-12 12:53:57 -05:00
Adrien Béraud c2a4f667a7 http: look for CA path in env 2020-11-12 12:53:03 -05:00
Adrien Béraud 05b95331d8 cmake: add CheckAtomic 2020-11-04 16:24:52 -05:00
20 changed files with 405 additions and 207 deletions

No files matched your search

+10 -10
View File
@@ -1,11 +1,13 @@
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.6)
set (opendht_VERSION_MINOR 1.9)
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
set (PACKAGE_VERSION ${opendht_VERSION})
set (VERSION "${opendht_VERSION}")
@@ -40,6 +42,7 @@ option (OPENDHT_DOCUMENTATION "Create and install the HTML based API documentati
# Dependencies
list (APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
if (NOT MSVC)
set (THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package (Threads)
find_package (PkgConfig REQUIRED)
find_package (GnuTLS 3.3 REQUIRED)
@@ -82,8 +85,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}")
include_directories(${OPENSSL_INCLUDE_DIRS})
message(STATUS "Found OpenSSL ${OPENSSL_VERSION} ${OPENSSL_INCLUDE_DIRS}")
include_directories(SYSTEM ${OPENSSL_INCLUDE_DIRS})
link_directories (${OPENSSL_LIBRARY_DIRS})
else ()
message(SEND_ERROR "OpenSSL is required for DHT proxy as specified")
@@ -300,9 +303,11 @@ 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 ()
@@ -323,13 +328,8 @@ 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)
set (MSC_COMPAT_DIR ${COMPAT_DIR}/msvc/)
list (APPEND opendht_SOURCES ${MSC_COMPAT_DIR}/unistd.h)
list (APPEND opendht_HEADERS src/compat/msvc/unistd.h)
endif ()
# Targets
+95
View File
@@ -0,0 +1,95 @@
# 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>
std::atomic<int64_t> v1;
std::atomic<int64_t> v2;
int main(int, char**) {
return v1 + v2;
}" ${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
View File
@@ -1,7 +1,7 @@
dnl define macros
m4_define([opendht_major_version], 2)
m4_define([opendht_minor_version], 1)
m4_define([opendht_patch_version], 6)
m4_define([opendht_patch_version], 9)
m4_define([opendht_version],
[opendht_major_version.opendht_minor_version.opendht_patch_version])
+2 -1
View File
@@ -314,6 +314,7 @@ class OPENDHT_PUBLIC OcspResponse
{
public:
OcspResponse(const uint8_t* dat_ptr, size_t dat_size);
OcspResponse(const std::string& response) : OcspResponse((const uint8_t*)response.data(), response.size()) {};
~OcspResponse();
Blob pack() const;
@@ -565,7 +566,7 @@ struct OPENDHT_PUBLIC Certificate {
* Return GnuTLS error code.
* https://www.gnutls.org/manual/html_node/Error-codes.html
*/
std::pair<Blob,Blob> generateOcspRequest(gnutls_x509_crt_t& issuer);
std::pair<std::string, Blob> generateOcspRequest(gnutls_x509_crt_t& issuer);
gnutls_x509_crt_t cert {nullptr};
std::shared_ptr<Certificate> issuer {};
+2
View File
@@ -96,6 +96,7 @@ public:
inline unsigned int id() const { return id_; };
bool is_open() const;
bool is_ssl() const;
void checkOcsp(bool check = true) { checkOcsp_ = check; }
void set_ssl_verification(const std::string& hostname, const asio::ssl::verify_mode verify_mode);
@@ -143,6 +144,7 @@ private:
std::unique_ptr<asio::steady_timer> timeout_timer_;
std::shared_ptr<dht::Logger> logger_;
bool checkOcsp_ {false};
};
/**
+16
View File
@@ -354,6 +354,22 @@ private:
OPENDHT_PUBLIC extern const HexMap hex_map;
inline std::string
toHex(const uint8_t* data, size_t size) {
std::string ret(size * 2, '\0');
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
View File
@@ -71,8 +71,8 @@ endif
libopendht_la_SOURCES += base64.h base64.cpp
if PROXY_CLIENT_OR_SERVER
libopendht_la_SOURCES += http.cpp
nobase_include_HEADERS += ../include/opendht/proxy.h ../include/opendht/http.h
libopendht_la_SOURCES += http.cpp compat/os_cert.cpp
nobase_include_HEADERS += ../include/opendht/proxy.h ../include/opendht/http.h compat/os_cert.h
endif
if ENABLE_PEER_DISCOVERY
+37 -51
View File
@@ -27,34 +27,20 @@
#endif
#include <openssl/ssl.h>
#ifdef __APPLE__
#ifdef TARGET_OS_OSX
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
#endif /*__APPLE__*/
#endif /*TARGET_OS_OSX*/
#ifdef _WIN32
#if EMBEDDED_ASN1_TIME_PARSE
#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)
{
@@ -131,24 +117,17 @@ ASN1_time_parse(const char* bytes, size_t len, struct tm* tm, int mode)
return (-1);
}
return (type);
return type;
}
#endif /*_WIN32*/
}
#endif /* EMBEDDED_ASN1_TIME_PARSE */
namespace dht {
namespace http {
void
addSystemCaCertificates(SSL_CTX* ctx, const std::shared_ptr<Logger>& logger)
PEMCache::PEMCache(const std::shared_ptr<Logger>& l)
: logger(l)
{
X509_STORE* store = SSL_CTX_get_cert_store(ctx);
if (store == nullptr) {
if (logger)
logger->e("couldn't get the context cert store");
return;
}
X509* x509cert;
#ifdef _WIN32
PCCERT_CONTEXT pContext = NULL;
HCERTSTORE hSystemStore;
@@ -159,19 +138,13 @@ addSystemCaCertificates(SSL_CTX* ctx, const std::shared_ptr<Logger>& logger)
return;
}
while (pContext = CertEnumCertificatesInStore(hSystemStore, pContext)) {
x509cert = nullptr;
const uint8_t* encoded_cert = pContext->pbCertEncoded;
x509cert = d2i_X509(nullptr, &encoded_cert, pContext->cbCertEncoded);
if (x509cert) {
if (X509_STORE_add_cert(store, x509cert) == 1) {
if (logger)
logger->d("local certificate added");
}
X509_free(x509cert);
}
X509Ptr x509cert(d2i_X509(nullptr, &encoded_cert, pContext->cbCertEncoded), &X509_free);
if (x509cert)
pems_.emplace_back(std::move(x509cert));
}
CertCloseStore(hSystemStore, 0);
#elif __APPLE__
#elif TARGET_OS_OSX
CFArrayRef result = NULL;
OSStatus osStatus;
@@ -179,7 +152,7 @@ addSystemCaCertificates(SSL_CTX* ctx, const std::shared_ptr<Logger>& logger)
if (logger) {
CFStringRef statusString = SecCopyErrorMessageString(osStatus, NULL);
logger->d("Error enumerating certificates: %s",
CFStringGetCStringPtr(statusString, kCFStringEncodingASCII));
CFStringGetCStringPtr(statusString, kCFStringEncodingASCII));
CFRelease(statusString);
}
if (result != NULL) {
@@ -189,7 +162,6 @@ addSystemCaCertificates(SSL_CTX* ctx, const std::shared_ptr<Logger>& logger)
}
CFDataRef rawData = NULL;
for (CFIndex i = 0; i < CFArrayGetCount(result); i++) {
x509cert = nullptr;
SecCertificateRef cert = (SecCertificateRef) CFArrayGetValueAtIndex(result, i);
rawData = SecCertificateCopyData(cert);
if (!rawData) {
@@ -198,14 +170,9 @@ addSystemCaCertificates(SSL_CTX* ctx, const std::shared_ptr<Logger>& logger)
break;
}
const uint8_t* rawDataPtr = CFDataGetBytePtr(rawData);
x509cert = d2i_X509(nullptr, &rawDataPtr, CFDataGetLength(rawData));
if (x509cert) {
if (X509_STORE_add_cert(store, x509cert) == 1) {
if (logger)
logger->d("local certificate added");
}
X509_free(x509cert);
}
X509Ptr x509cert(d2i_X509(nullptr, &rawDataPtr, CFDataGetLength(rawData)), &X509_free);
if (x509cert)
pems_.emplace_back(std::move(x509cert));
CFRelease(rawData);
rawData = NULL;
}
@@ -215,7 +182,26 @@ addSystemCaCertificates(SSL_CTX* ctx, const std::shared_ptr<Logger>& logger)
if (rawData != NULL) {
CFRelease(rawData);
}
#endif /*__APPLE__, _WIN32*/
#endif /*TARGET_OS_OSX, _WIN32*/
}
void
PEMCache::fillX509Store(SSL_CTX* ctx)
{
if (logger)
logger->w("adding %d decoded certs to X509 store", pems_.size());
X509_STORE* store = SSL_CTX_get_cert_store(ctx);
if (store == nullptr) {
if (logger)
logger->e("couldn't get the context cert store");
return;
}
for (const auto& pem : pems_) {
if (X509_STORE_add_cert(store, pem.get()) == 1)
continue;
if (logger)
logger->d("couldn't add local certificate");
}
}
} /*namespace http*/
+47 -4
View File
@@ -24,15 +24,58 @@
#include <openssl/x509.h>
#ifdef _WIN32
#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
#define V_ASN1_UTCTIME 23
#define V_ASN1_GENERALIZEDTIME 24
#define timegm _mkgmtime
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.
*/
int ASN1_time_parse(const char* bytes, size_t len, struct tm* tm, int mode);
#endif /*_WIN32*/
}
#endif
namespace dht {
namespace http {
void addSystemCaCertificates(SSL_CTX* ctx, const std::shared_ptr<Logger>& logger);
// A singleton class used to cache the decoded certificates
// loaded from local cert stores that need to be added to the
// ssl context prior to each request.
class PEMCache
{
PEMCache(const std::shared_ptr<Logger>& l);
using X509Ptr = std::unique_ptr<X509, void(*)(X509*)>;
std::vector<X509Ptr> pems_;
std::shared_ptr<Logger> logger;
public:
static PEMCache& instance(const std::shared_ptr<Logger>& l)
{
static PEMCache instance_(l);
return instance_;
}
void fillX509Store(SSL_CTX* ctx);
};
}
} // namespace dht
+47 -70
View File
@@ -1034,7 +1034,7 @@ Certificate::getPreferredDigest() const
return getPublicKey().getPreferredDigest();
}
std::pair<Blob,Blob>
std::pair<std::string, Blob>
Certificate::generateOcspRequest(gnutls_x509_crt_t& issuer)
{
gnutls_ocsp_req_t rreq;
@@ -1042,10 +1042,10 @@ Certificate::generateOcspRequest(gnutls_x509_crt_t& issuer)
if (err < 0)
throw CryptoException(gnutls_strerror(err));
std::unique_ptr<struct gnutls_ocsp_req_int, decltype(&gnutls_ocsp_req_deinit)> req(rreq, &gnutls_ocsp_req_deinit);
err = gnutls_ocsp_req_add_cert(req.get(), GNUTLS_DIG_SHA512, issuer, cert);
err = gnutls_ocsp_req_add_cert(req.get(), GNUTLS_DIG_SHA1, issuer, cert);
if (err < 0)
throw CryptoException(gnutls_strerror(err));
Blob noncebuf(64);
Blob noncebuf(32);
gnutls_datum_t nonce = { noncebuf.data(), (unsigned)noncebuf.size() };
err = gnutls_rnd(GNUTLS_RND_NONCE, nonce.data, nonce.size);
err = gnutls_ocsp_req_set_nonce(req.get(), 0, &nonce);
@@ -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));
Blob ret(rdata.data, rdata.data + rdata.size);
std::string ret((char*)rdata.data, (char*)rdata.data + rdata.size);
gnutls_free(rdata.data);
return std::make_pair<Blob,Blob>(std::move(ret), std::move(noncebuf));
return std::make_pair<std::string, Blob>(std::move(ret), std::move(noncebuf));
}
// PrivateKey
@@ -1162,13 +1162,11 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden
Certificate ret {cert};
setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60);
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_key(cert, key.x509_key)) {
throw CryptoException(std::string("Error when setting certificate key ") + gnutls_strerror(err));
}
if (gnutls_x509_crt_set_version(cert, 3) != GNUTLS_E_SUCCESS) {
std::cerr << "Error when setting certificate version" << 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));
}
// TODO: compute the subject key using the recommended RFC method
@@ -1193,18 +1191,15 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden
if (ca.first && ca.second) {
if (not ca.second->isCA()) {
// Signing certificate must be CA.
return {};
throw CryptoException("Signing certificate must be CA");
}
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 {};
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));
}
ret.issuer = ca.second;
} else {
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 {};
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));
}
}
@@ -1306,65 +1301,47 @@ OcspResponse::getCertificateStatus() const
gnutls_ocsp_verify_reason_t
OcspResponse::verifyDirect(const Certificate& crt, const Blob& nonce)
{
// 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;
// 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 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));
#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.
*/
// Check whether the OCSP response is about the provided certificate.
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);
throw CryptoException(gnutls_strerror(ret));
// Verify signature of the Basic OCSP response against the public key in the issuer certificate.
unsigned int verify = 0;
ret = gnutls_ocsp_resp_verify_direct(response, crt.issuer->cert, &verify, 0);
if (ret < 0)
goto end;
ret = gnutls_ocsp_resp_check_crt(response, 0 /*index*/, crt.cert);
throw CryptoException(gnutls_strerror(ret));
// 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 (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;
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
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)
goto end;
// Ensure no replay attack has been done
if (rnonce.size != nonce.size() || memcmp(nonce.data(), rnonce.data, nonce.size()) != 0){
ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
goto end;
}
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;
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));
}
gnutls_free(rnonce.data);
return (gnutls_ocsp_verify_reason_t) verify;
}
// RevocationList
+2
View File
@@ -636,6 +636,8 @@ DhtProxyClient::queryProxyInfo(const Sp<InfoState>& infoState, const Sp<http::Re
logger_->d("[proxy:client] [status] query ipv%i info", family == AF_INET ? 4 : 6);
try {
auto request = std::make_shared<http::Request>(httpContext_, resolver, family);
if (serverCertificate_)
request->set_certificate_authority(serverCertificate_);
auto reqid = request->id();
request->set_method(restinio::http_method_get());
setHeaderFields(*request);
+71 -41
View File
@@ -31,10 +31,14 @@
#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 {
@@ -99,22 +103,44 @@ 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_ = 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__)
addSystemCaCertificates(ssl_ctx_->native_handle(), l);
#else
ssl_ctx_->set_default_verify_paths();
#endif
ssl_ctx_ = newTlsClientContext(l);
ssl_socket_ = std::make_unique<ssl_socket_t>(ctx_, ssl_ctx_);
if (logger_)
logger_->d("[connection:%i] start https session", id_);
logger_->d("[connection:%i] start https session with system CA", id_);
}
else {
socket_ = std::make_unique<socket_t>(ctx);
@@ -127,23 +153,20 @@ 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
addSystemCaCertificates(ssl_ctx_->native_handle(), l);
#else
ssl_ctx_->set_default_verify_paths();
#endif
asio::error_code ec;
if (server_ca){
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);
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());
logger_->d("[connection:%i] start https with custom CA %s", id_, server_ca->getUID().c_str());
} else {
ssl_ctx_ = newTlsClientContext(l);
if (logger_)
logger_->d("[connection:%i] start https session with system CA", id_);
}
if (identity.first){
auto key = identity.first->serialize();
@@ -237,7 +260,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::vector<uint8_t> data;
std::string data;
std::string url;
};
@@ -277,7 +300,7 @@ ocspRequestFromCert(STACK_OF(X509)* fullchain, const std::shared_ptr<Logger>& lo
auto request = std::make_unique<OscpRequestInfo>();
request->req = OscpRequestPtr(OCSP_REQUEST_new(), &OCSP_REQUEST_free);
request->url = strdup(url);
request->url = url;
X509_email_free(urls);
OCSP_CERTID* id = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
@@ -307,7 +330,7 @@ ocspRequestFromCert(STACK_OF(X509)* fullchain, const std::shared_ptr<Logger>& lo
logger->e("Unable to allocte memory");
return {};
}
request->data = std::vector<uint8_t>(data, data+size);
request->data = std::string((char*)data, (char*)data+size);
free(data);
return request;
}
@@ -319,9 +342,6 @@ ocspValidateResponse(const OscpRequestInfo& info, STACK_OF(X509)* fullchain, con
const uint8_t* p = (const uint8_t*)response.data();
int status, cert_status=0, crl_reason=0;
time_t now, rev_t = -1, this_t, next_t;
OCSP_RESPONSE *resp;
OCSP_BASICRESP *bresp;
OCSP_CERTID *cid;
X509* cert = cert_from_chain(fullchain);
if (cert == nullptr) {
@@ -335,32 +355,39 @@ ocspValidateResponse(const OscpRequestInfo& info, STACK_OF(X509)* fullchain, con
logger->e("Unable to find issuer for cert");
return false;
}
if ((cid = OCSP_cert_to_id(nullptr, cert, issuer)) == nullptr) {
OCSP_CERTID *cidr;
if ((cidr = OCSP_cert_to_id(nullptr, cert, issuer)) == nullptr) {
if (logger)
logger->e("Unable to get issuer cert/CID");
return false;
}
std::unique_ptr<OCSP_CERTID, decltype(&OCSP_CERTID_free)> cid(cidr, &OCSP_CERTID_free);
if ((resp = d2i_OCSP_RESPONSE(nullptr, &p, response.size())) == nullptr) {
OCSP_RESPONSE *r;
if ((r = d2i_OCSP_RESPONSE(nullptr, &p, response.size())) == nullptr) {
if (logger)
logger->e("OCSP response unserializable");
return false;
}
std::unique_ptr<OCSP_RESPONSE, decltype(&OCSP_RESPONSE_free)> resp(r, &OCSP_RESPONSE_free);
if ((bresp = OCSP_response_get1_basic(resp)) == nullptr) {
OCSP_BASICRESP *brespr;
if ((brespr = OCSP_response_get1_basic(resp.get())) == nullptr) {
if (logger)
logger->e("Failed to load OCSP response");
return false;
}
std::unique_ptr<OCSP_BASICRESP, decltype(&OCSP_BASICRESP_free)> bresp(brespr, &OCSP_BASICRESP_free);
if (OCSP_basic_verify(bresp, fullchain, store, OCSP_TRUSTOTHER) != 1) {
if (OCSP_basic_verify(bresp.get(), fullchain, store, OCSP_TRUSTOTHER) != 1) {
if (logger)
logger->w("OCSP verify failed");
return false;
}
printf("OCSP response signature validated\n");
status = OCSP_response_status(resp);
status = OCSP_response_status(resp.get());
if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
if (logger)
logger->w("OCSP Failure: code %d (%s)", status, OCSP_response_status_str(status));
@@ -368,13 +395,13 @@ ocspValidateResponse(const OscpRequestInfo& info, STACK_OF(X509)* fullchain, con
}
// Check the nonce if we sent one
if (OCSP_check_nonce(info.req.get(), bresp) <= 0) {
if (OCSP_check_nonce(info.req.get(), bresp.get()) <= 0) {
if (logger)
logger->w("No OCSP nonce, or mismatch");
return false;
}
if (OCSP_resp_find_status(bresp, cid, &cert_status, &crl_reason,
if (OCSP_resp_find_status(bresp.get(), cid.get(), &cert_status, &crl_reason,
&revtime, &thisupd, &nextupd) != 1) {
if (logger)
logger->w("OCSP verify failed: no result for cert");
@@ -455,7 +482,7 @@ Connection::set_ssl_verification(const std::string& hostname, const asio::ssl::v
ssl_socket_->asio_ssl_stream().set_verify_mode(verify_mode);
if (verify_mode != asio::ssl::verify_none) {
ssl_socket_->asio_ssl_stream().set_verify_callback([
id = id_, logger = logger_, hostname
id = id_, logger = logger_, hostname, checkOcsp = checkOcsp_
] (bool preverified, asio::ssl::verify_context& ctx) -> bool {
X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
if (logger) {
@@ -470,23 +497,26 @@ Connection::set_ssl_verification(const std::string& hostname, const asio::ssl::v
auto verify_ec = X509_STORE_CTX_get_error(ctx.native_handle());
if (verify_ec != 0 /*X509_V_OK*/ and logger)
logger->e("[http::connection:%i] ssl verification error=%i %d", id, verify_ec, verified);
if (verified) {
auto chain = X509_STORE_CTX_get1_chain(ctx.native_handle());
if (auto ocspInfo = ocspRequestFromCert(chain, logger)) {
if (verified and checkOcsp) {
std::unique_ptr<stack_st_X509, void(*)(stack_st_X509*)> chain(
X509_STORE_CTX_get1_chain(ctx.native_handle()),
[](stack_st_X509* c){ sk_X509_pop_free(c, X509_free); });
if (auto ocspInfo = ocspRequestFromCert(chain.get(), logger)) {
if (logger)
logger->w("[http::connection:%i] TLS OCSP server: %s, request size: %zu", id, ocspInfo->url.c_str(), ocspInfo->data.size());
bool ocspVerified = false;
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, ctx.native_handle()->ctx, logger);
ocspVerified = ocspValidateResponse(*ocspInfo, chain.get(), ocspResp.body, X509_STORE_CTX_get0_store(ctx.native_handle()), logger);
} else {
if (logger)
logger->w("[http::connection:%i] TLS OCSP check error", id);
}
}, logger);
ocspReq->set_method(restinio::http_method_post());
ocspReq->set_body({ocspInfo->data.begin(), ocspInfo->data.end()});
ocspReq->set_header_field(restinio::http_field_t::content_type, "application/ocsp-request");
ocspReq->set_body(ocspInfo->data);
ocspReq->send();
io_ctx.run();
if (not ocspVerified)
@@ -1354,7 +1384,7 @@ Request::onHeadersComplete() {
}
bool startsWith(const std::string& haystack, const std::string& needle) {
return needle.length() <= haystack.length()
return needle.length() <= haystack.length()
&& std::equal(needle.begin(), needle.end(), haystack.begin());
}
+7 -6
View File
@@ -39,8 +39,10 @@ public:
}
static ValueCallback cacheCallback(ValueCallback&& cb, std::function<void()>&& onCancel) {
auto cache = std::make_shared<OpValueCache>(std::forward<ValueCallback>(cb));
return [cache, onCancel](const std::vector<Sp<Value>>& vals, bool expired){
return [
cache = std::make_shared<OpValueCache>(std::forward<ValueCallback>(cb)),
onCancel = std::move(onCancel)
](const std::vector<Sp<Value>>& vals, bool expired){
auto ret = cache->onValue(vals, expired);
if (not ret)
onCancel();
@@ -49,10 +51,9 @@ public:
}
bool onValue(const std::vector<Sp<Value>>& vals, bool expired, const system_clock::time_point& t = system_clock::time_point::min()) {
if (expired)
return onValuesExpired(vals, t);
else
return onValuesAdded(vals, t);
return expired
? onValuesExpired(vals, t)
: onValuesAdded(vals, t);
}
bool onValuesAdded(const std::vector<Sp<Value>>& vals, const system_clock::time_point& t = system_clock::time_point::min());
+1 -4
View File
@@ -76,10 +76,7 @@ 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 << std::hex;
for (auto i : v.data)
s << std::setfill('0') << std::setw(2) << (unsigned)i;
s << std::dec;
s << toHex(v.data.data(), v.data.size());
} else {
s << v.data.size() << " bytes";
}
+2 -3
View File
@@ -192,11 +192,10 @@ private:
auto v = values.find(vid);
if (v == values.end())
return {};
const std::vector<Sp<Value>> val {std::move(v->second.data)};
std::vector<Sp<Value>> val {std::move(v->second.data)};
values.erase(v);
auto cb = callback;
CallbackQueue ret;
ret.emplace_back([cb, val]{
ret.emplace_back([cb = callback, val = std::move(val)]{
if (cb) cb(val, true);
});
return ret;
+5 -5
View File
@@ -46,15 +46,15 @@ DhtProxyTester::setUp() {
auto serverCAIdentity = dht::crypto::generateEcIdentity("DHT Node CA");
dht::ProxyServerConfig serverConfig;
serverConfig.identity = dht::crypto::generateIdentity("DHT Node", serverCAIdentity);
//serverConfig.identity = dht::crypto::generateIdentity("DHT Node", serverCAIdentity);
serverConfig.port = 8080;
serverConfig.pushServer = "127.0.0.1:8090";
// serverConfig.pushServer = "127.0.0.1:8090";
serverProxy = std::make_unique<dht::DhtProxyServer>(nodeProxy, serverConfig);
clientConfig.server_ca = serverCAIdentity.second;
/*clientConfig.server_ca = serverCAIdentity.second;
clientConfig.client_identity = dht::crypto::generateIdentity("DhtProxyTester");
clientConfig.push_node_id = "dhtnode";
clientConfig.proxy_server = "https://127.0.0.1:8080";
clientConfig.push_node_id = "dhtnode";*/
clientConfig.proxy_server = "http://127.0.0.1:8080";//"https://127.0.0.1:8080";
}
void
+9 -1
View File
@@ -73,7 +73,7 @@ InfoHashTester::testConstructors() {
}
void
InfoHashTester::testComperators() {
InfoHashTester::testComparators() {
auto nullHash = dht::InfoHash();
auto minHash = dht::InfoHash("0000000000000000000000000000000000111110");
auto maxHash = dht::InfoHash("0111110000000000000000000000000000000000");
@@ -136,6 +136,14 @@ InfoHashTester::testXorCmp() {
CPPUNIT_ASSERT_EQUAL(maxHash.xorCmp(minHash, nullHash), 1);
}
void
InfoHashTester::testHex() {
const std::string TEST_HASH_STR("01b20304d5060708090a010203e05060708090ae");
dht::InfoHash TEST_HASH(TEST_HASH_STR);
CPPUNIT_ASSERT_EQUAL(TEST_HASH_STR, TEST_HASH.toString());
CPPUNIT_ASSERT_EQUAL(TEST_HASH_STR, dht::toHex(TEST_HASH.data(), TEST_HASH.size()));
}
void
InfoHashTester::tearDown() {
+7 -2
View File
@@ -28,10 +28,11 @@ namespace test {
class InfoHashTester : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(InfoHashTester);
CPPUNIT_TEST(testConstructors);
CPPUNIT_TEST(testComperators);
CPPUNIT_TEST(testComparators);
CPPUNIT_TEST(testLowBit);
CPPUNIT_TEST(testCommonBits);
CPPUNIT_TEST(testXorCmp);
CPPUNIT_TEST(testHex);
CPPUNIT_TEST_SUITE_END();
public:
@@ -50,7 +51,7 @@ class InfoHashTester : public CppUnit::TestFixture {
/**
* Test compare operators
*/
void testComperators();
void testComparators();
/**
* Test lowbit method
*/
@@ -64,6 +65,10 @@ class InfoHashTester : public CppUnit::TestFixture {
*/
void testXorCmp();
/**
* Test hex conversion
*/
void testHex();
};
} // namespace test
+8 -2
View File
@@ -39,8 +39,14 @@ endif ()
install (TARGETS dhtnode dhtscanner dhtchat RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
if (OPENDHT_SYSTEMD)
execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} systemd --variable=systemdsystemunitdir
OUTPUT_VARIABLE SYSTEMD_UNIT_INSTALL_DIR)
if (NOT DEFINED OPENDHT_SYSTEMD_UNIT_FILE_LOCATION)
execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} systemd --variable=systemdsystemunitdir
OUTPUT_VARIABLE SYSTEMD_UNIT_INSTALL_DIR)
message("-- Using Systemd unit installation directory by pkg-config: " ${SYSTEMD_UNIT_INSTALL_DIR})
else()
message("-- Using Systemd unit installation directory requested: " ${OPENDHT_SYSTEMD_UNIT_FILE_LOCATION})
set(SYSTEMD_UNIT_INSTALL_DIR ${OPENDHT_SYSTEMD_UNIT_FILE_LOCATION})
endif()
string(REGEX REPLACE "[ \t\n]+" "" SYSTEMD_UNIT_INSTALL_DIR "${SYSTEMD_UNIT_INSTALL_DIR}")
set (systemdunitdir "${SYSTEMD_UNIT_INSTALL_DIR}")
+34 -4
View File
@@ -1,14 +1,44 @@
[Unit]
Description=OpenDHT standalone node
Documentation=man:dhtnode(1)
After=network.target
[Service]
EnvironmentFile=@sysconfdir@/dhtnode.conf
ExecStart=@bindir@/dhtnode -s $DHT_ARGS
KillMode=process
Restart=on-failure
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
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
[Install]
WantedBy=multi-user.target