mirror of
https://github.com/savoirfairelinux/opendht.git
synced 2026-11-09 21:07:17 +00:00
Compare commits
20
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ac451a5de | ||
|
|
9efb8bb662 | ||
|
|
f0aee6f909 | ||
|
|
f72bfc9df2 | ||
|
|
c9ebfd1119 | ||
|
|
cf1874baaa | ||
|
|
c221cfdafe | ||
|
|
31b84e6d92 | ||
|
|
ae05bc8ea5 | ||
|
|
acbf7cfcf0 | ||
|
|
8250116946 | ||
|
|
45e9458373 | ||
|
|
2623b86274 | ||
|
|
2e1dda8189 | ||
|
|
e26256b819 | ||
|
|
18e59ad7c8 | ||
|
|
a7a3d23f50 | ||
|
|
323a2b5093 | ||
|
|
563811ebf8 | ||
|
|
190c7f2063 |
No files matched your search
+1
-1
@@ -4,7 +4,7 @@ include(CMakeDependentOption)
|
||||
|
||||
project (opendht)
|
||||
set (opendht_VERSION_MAJOR 2)
|
||||
set (opendht_VERSION_MINOR 1.3)
|
||||
set (opendht_VERSION_MINOR 1.4)
|
||||
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
|
||||
set (PACKAGE_VERSION ${opendht_VERSION})
|
||||
set (VERSION "${opendht_VERSION}")
|
||||
|
||||
+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], 3)
|
||||
m4_define([opendht_patch_version], 4)
|
||||
m4_define([opendht_version],
|
||||
[opendht_major_version.opendht_minor_version.opendht_patch_version])
|
||||
|
||||
|
||||
+1
-1
@@ -2,5 +2,5 @@ FROM aberaud/opendht-deps
|
||||
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
RUN git clone https://github.com/savoirfairelinux/opendht.git \
|
||||
&& cd opendht && mkdir build && cd build \
|
||||
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_LTO=On && make -j8 && make install \
|
||||
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_LTO=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On && make -j8 && make install \
|
||||
&& cd ../.. && rm -rf opendht
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM docker.pkg.github.com/savoirfairelinux/opendht/opendht-deps-bionic:2.0.0
|
||||
FROM docker.pkg.github.com/savoirfairelinux/opendht/opendht-deps-bionic:2.1.3
|
||||
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
|
||||
RUN git clone https://github.com/savoirfairelinux/opendht.git \
|
||||
|
||||
@@ -17,11 +17,11 @@ RUN apt-get update && apt-get install -y \
|
||||
|
||||
RUN echo "*** Downloading RESTinio ***" \
|
||||
&& mkdir restinio && cd restinio \
|
||||
&& wget https://github.com/aberaud/restinio/archive/a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
|
||||
&& ls -l && tar -xzf a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
|
||||
&& cd restinio-a7a10e419d9089c5b8ee63f5e3098c892f22fae4/dev \
|
||||
&& wget https://github.com/aberaud/restinio/archive/2c0b6f5e5ba04d7a74e8406a3df1fd433680599d.tar.gz \
|
||||
&& ls -l && tar -xzf 2c0b6f5e5ba04d7a74e8406a3df1fd433680599d.tar.gz \
|
||||
&& cd restinio-2c0b6f5e5ba04d7a74e8406a3df1fd433680599d/dev \
|
||||
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
|
||||
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
|
||||
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
|
||||
&& make -j8 && make install \
|
||||
&& cd ../../ && rm -rf restinio*
|
||||
&& cd ../../.. && rm -rf restinio
|
||||
@@ -18,9 +18,9 @@ ENV CXX c++
|
||||
|
||||
RUN echo "*** Downloading RESTinio ***" \
|
||||
&& mkdir restinio && cd restinio \
|
||||
&& wget https://github.com/aberaud/restinio/archive/a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
|
||||
&& ls -l && tar -xzf a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
|
||||
&& cd restinio-a7a10e419d9089c5b8ee63f5e3098c892f22fae4/dev \
|
||||
&& wget https://github.com/aberaud/restinio/archive/2c0b6f5e5ba04d7a74e8406a3df1fd433680599d.tar.gz \
|
||||
&& ls -l && tar -xzf 2c0b6f5e5ba04d7a74e8406a3df1fd433680599d.tar.gz \
|
||||
&& cd restinio-2c0b6f5e5ba04d7a74e8406a3df1fd433680599d/dev \
|
||||
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
|
||||
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
|
||||
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
|
||||
|
||||
@@ -2,5 +2,5 @@ FROM aberaud/opendht-deps-llvm
|
||||
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
RUN git clone https://github.com/savoirfairelinux/opendht.git \
|
||||
&& cd opendht && mkdir build && cd build \
|
||||
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_LTO=On && make -j8 && make install \
|
||||
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_LTO=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On && make -j8 && make install \
|
||||
&& cd ../.. && rm -rf opendht
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -26,6 +27,7 @@ extern "C" {
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <gnutls/abstract.h>
|
||||
#include <gnutls/x509.h>
|
||||
#include <gnutls/ocsp.h>
|
||||
}
|
||||
|
||||
#include <vector>
|
||||
@@ -196,7 +198,6 @@ private:
|
||||
//friend dht::crypto::Identity dht::crypto::generateIdentity(const std::string&, dht::crypto::Identity, unsigned key_length);
|
||||
};
|
||||
|
||||
|
||||
class OPENDHT_PUBLIC RevocationList
|
||||
{
|
||||
using clock = std::chrono::system_clock;
|
||||
@@ -309,6 +310,36 @@ private:
|
||||
gnutls_x509_crq_t request {nullptr};
|
||||
};
|
||||
|
||||
class OPENDHT_PUBLIC OcspResponse
|
||||
{
|
||||
public:
|
||||
OcspResponse(const uint8_t* dat_ptr, size_t dat_size);
|
||||
~OcspResponse();
|
||||
|
||||
Blob pack() const;
|
||||
/*
|
||||
* Get OCSP Response in readable format.
|
||||
*/
|
||||
std::string toString(const bool compact = true) const;
|
||||
|
||||
/*
|
||||
* Get OCSP response certificate status.
|
||||
* Return certificate status.
|
||||
* http://www.gnu.org/software/gnutls/reference/gnutls-ocsp.html#gnutls-ocsp-cert-status-t
|
||||
*/
|
||||
gnutls_ocsp_cert_status_t getCertificateStatus() const;
|
||||
|
||||
/*
|
||||
* Verify OCSP response.
|
||||
* Return OCSP verify reason.
|
||||
* http://www.gnu.org/software/gnutls/reference/gnutls-ocsp.html#gnutls-ocsp-verify-reason-t
|
||||
*/
|
||||
gnutls_ocsp_verify_reason_t verifyDirect(const Certificate& crt, const Blob& nonce);
|
||||
|
||||
private:
|
||||
gnutls_ocsp_resp_t response;
|
||||
};
|
||||
|
||||
struct OPENDHT_PUBLIC Certificate {
|
||||
Certificate() noexcept {}
|
||||
|
||||
@@ -434,6 +465,8 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
/** Same as getPublicKey().getLongId() */
|
||||
PkId getLongId() const;
|
||||
|
||||
Blob getSerialNumber() const;
|
||||
|
||||
/** Read certificate Common Name (CN) */
|
||||
std::string getName() const;
|
||||
|
||||
@@ -527,8 +560,16 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
|
||||
gnutls_digest_algorithm_t getPreferredDigest() const;
|
||||
|
||||
/*
|
||||
* Generate OCSP request.
|
||||
* Return GnuTLS error code.
|
||||
* https://www.gnutls.org/manual/html_node/Error-codes.html
|
||||
*/
|
||||
std::pair<Blob,Blob> generateOcspRequest(gnutls_x509_crt_t& issuer);
|
||||
|
||||
gnutls_x509_crt_t cert {nullptr};
|
||||
std::shared_ptr<Certificate> issuer {};
|
||||
std::shared_ptr<OcspResponse> ocspResponse;
|
||||
private:
|
||||
Certificate(const Certificate&) = delete;
|
||||
Certificate& operator=(const Certificate&) = delete;
|
||||
|
||||
@@ -95,7 +95,7 @@ public:
|
||||
bool is_open() const;
|
||||
bool is_ssl() const;
|
||||
|
||||
void set_ssl_verification(const asio::ip::tcp::endpoint& endpoint, const asio::ssl::verify_mode verify_mode);
|
||||
void set_ssl_verification(const std::string& hostname, const asio::ssl::verify_mode verify_mode);
|
||||
|
||||
asio::streambuf& input();
|
||||
std::istream& data() { return istream_; }
|
||||
@@ -226,12 +226,15 @@ public:
|
||||
using OnStatusCb = std::function<void(unsigned status_code)>;
|
||||
using OnDataCb = std::function<void(const char* at, size_t length)>;
|
||||
using OnStateChangeCb = std::function<void(State state, const Response& response)>;
|
||||
using OnJsonCb = std::function<void(Json::Value value, unsigned status_code)>;
|
||||
using OnJsonCb = std::function<void(Json::Value value, const Response& response)>;
|
||||
using OnDoneCb = std::function<void(const Response& response)>;
|
||||
|
||||
// resolves implicitly
|
||||
Request(asio::io_context& ctx, const std::string& url, const Json::Value& json, OnJsonCb jsoncb,
|
||||
std::shared_ptr<dht::Logger> logger = {});
|
||||
Request(asio::io_context& ctx, const std::string& url, OnJsonCb jsoncb,
|
||||
std::shared_ptr<dht::Logger> logger = {});
|
||||
|
||||
Request(asio::io_context& ctx, const std::string& url, std::shared_ptr<dht::Logger> logger = {});
|
||||
Request(asio::io_context& ctx, const std::string& host, const std::string& service,
|
||||
const bool ssl = false, std::shared_ptr<dht::Logger> logger = {});
|
||||
|
||||
@@ -211,6 +211,7 @@ private:
|
||||
|
||||
public:
|
||||
using RequestCb = std::function<void(const Request&, RequestAnswer&&)>;
|
||||
using RequestErrorCb = std::function<bool(const Request&, DhtProtocolException&&)>;
|
||||
using RequestExpiredCb = std::function<void(const Request&, bool)>;
|
||||
|
||||
NetworkEngine(const Sp<Logger>& log, std::mt19937_64& rd, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock);
|
||||
@@ -361,10 +362,9 @@ public:
|
||||
const InfoHash& hash,
|
||||
const Query& query,
|
||||
const Blob& token,
|
||||
Sp<Request> previous,
|
||||
Tid socketId,
|
||||
RequestCb&& on_done,
|
||||
RequestExpiredCb&& on_expired,
|
||||
SocketCb&& socket_cb);
|
||||
RequestExpiredCb&& on_expired);
|
||||
/**
|
||||
* Send a "announce" request to a given node.
|
||||
*
|
||||
@@ -403,6 +403,7 @@ public:
|
||||
const Value::Id& vid,
|
||||
const Blob& token,
|
||||
RequestCb&& on_done,
|
||||
RequestErrorCb&& on_error,
|
||||
RequestExpiredCb&& on_expired);
|
||||
/**
|
||||
* Send a "update" request to a given node. Used for Listen operations
|
||||
|
||||
+161
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -25,6 +26,7 @@ extern "C" {
|
||||
#include <gnutls/x509.h>
|
||||
#include <nettle/gcm.h>
|
||||
#include <nettle/aes.h>
|
||||
#include <gnutls/crypto.h>
|
||||
|
||||
#include <argon2.h>
|
||||
}
|
||||
@@ -875,6 +877,18 @@ Certificate::getLongId() const
|
||||
#endif
|
||||
}
|
||||
|
||||
Blob
|
||||
Certificate::getSerialNumber() const
|
||||
{
|
||||
if (not cert)
|
||||
return {};
|
||||
// extract from certificate
|
||||
unsigned char serial[64];
|
||||
auto size = sizeof(serial);
|
||||
gnutls_x509_crt_get_serial(cert, &serial, &size);
|
||||
return {serial, serial + size};
|
||||
}
|
||||
|
||||
std::string
|
||||
Certificate::getName() const
|
||||
{
|
||||
@@ -1020,6 +1034,32 @@ Certificate::getPreferredDigest() const
|
||||
return getPublicKey().getPreferredDigest();
|
||||
}
|
||||
|
||||
std::pair<Blob,Blob>
|
||||
Certificate::generateOcspRequest(gnutls_x509_crt_t& issuer)
|
||||
{
|
||||
gnutls_ocsp_req_t rreq;
|
||||
int err = gnutls_ocsp_req_init(&rreq);
|
||||
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);
|
||||
if (err < 0)
|
||||
throw CryptoException(gnutls_strerror(err));
|
||||
Blob noncebuf(64);
|
||||
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);
|
||||
if (err < 0)
|
||||
throw CryptoException(gnutls_strerror(err));
|
||||
gnutls_datum_t rdata;
|
||||
err = gnutls_ocsp_req_export(req.get(), &rdata);
|
||||
if (err != 0)
|
||||
throw CryptoException(gnutls_strerror(err));
|
||||
Blob ret(rdata.data, rdata.data + rdata.size);
|
||||
gnutls_free(rdata.data);
|
||||
return std::make_pair<Blob,Blob>(std::move(ret), std::move(noncebuf));
|
||||
}
|
||||
|
||||
// PrivateKey
|
||||
|
||||
PrivateKey
|
||||
@@ -1206,6 +1246,127 @@ Certificate::getRevocationLists() const
|
||||
return ret;
|
||||
}
|
||||
|
||||
// OcspResponse
|
||||
|
||||
OcspResponse::OcspResponse(const uint8_t* dat_ptr, size_t dat_size)
|
||||
{
|
||||
int ret = gnutls_ocsp_resp_init(&response);
|
||||
if (ret < 0)
|
||||
throw CryptoException(gnutls_strerror(ret));
|
||||
gnutls_datum_t dat = {(unsigned char*)dat_ptr,(unsigned int)dat_size};
|
||||
ret = gnutls_ocsp_resp_import(response, &dat);
|
||||
if (ret < 0){
|
||||
gnutls_ocsp_resp_deinit(response);
|
||||
throw CryptoException(gnutls_strerror(ret));
|
||||
}
|
||||
}
|
||||
|
||||
OcspResponse::~OcspResponse()
|
||||
{
|
||||
gnutls_ocsp_resp_deinit(response);
|
||||
}
|
||||
|
||||
Blob
|
||||
OcspResponse::pack() const
|
||||
{
|
||||
gnutls_datum_t dat;
|
||||
int ret = gnutls_ocsp_resp_export(response, &dat);
|
||||
if (ret < 0)
|
||||
throw CryptoException(gnutls_strerror(ret));
|
||||
return {dat.data, dat.data + dat.size};
|
||||
}
|
||||
|
||||
std::string
|
||||
OcspResponse::toString(const bool compact) const
|
||||
{
|
||||
int ret;
|
||||
std::string str;
|
||||
gnutls_datum_t dat;
|
||||
ret = gnutls_ocsp_resp_print(response, compact ? GNUTLS_OCSP_PRINT_COMPACT : GNUTLS_OCSP_PRINT_FULL, &dat);
|
||||
if (ret == 0)
|
||||
str = std::string((const char*)dat.data, (size_t)dat.size);
|
||||
gnutls_free(dat.data);
|
||||
if (ret < 0)
|
||||
throw CryptoException(gnutls_strerror(ret));
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
gnutls_ocsp_cert_status_t
|
||||
OcspResponse::getCertificateStatus() const
|
||||
{
|
||||
int ret;
|
||||
unsigned int status;
|
||||
ret = gnutls_ocsp_resp_get_single(response, 0, NULL, NULL, NULL, NULL, &status, NULL, NULL, NULL, NULL);
|
||||
if (ret < 0)
|
||||
throw CryptoException(gnutls_strerror(ret));
|
||||
return (gnutls_ocsp_cert_status_t) status;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
#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)
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
// RevocationList
|
||||
|
||||
RevocationList::RevocationList()
|
||||
|
||||
+38
-31
@@ -490,7 +490,29 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr) {
|
||||
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] sending 'refresh' (vid: %d)",
|
||||
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
|
||||
sn->acked[a.value->id] = {
|
||||
network_engine.sendRefreshValue(sn->node, sr->id, a.value->id, sn->token, onDone, onExpired),
|
||||
network_engine.sendRefreshValue(sn->node, sr->id, a.value->id, sn->token, onDone,
|
||||
[this, ws, node=sn->node, v=a.value,
|
||||
onDone,
|
||||
onExpired,
|
||||
created = a.permanent ? time_point::max() : a.created,
|
||||
next_refresh_time
|
||||
](const net::Request& req, net::DhtProtocolException&& e){
|
||||
if (e.getCode() == net::DhtProtocolException::NOT_FOUND) {
|
||||
if (logger_)
|
||||
logger_->e(node->id, "[node %s] returned error 404: storage not found", node->toString().c_str());
|
||||
if (auto sr = ws.lock()) {
|
||||
if (auto sn = sr->getNode(node)) {
|
||||
sn->acked[v->id] = {
|
||||
network_engine.sendAnnounceValue(sn->node, sr->id, v, created, sn->token, onDone, onExpired),
|
||||
next_refresh_time
|
||||
};
|
||||
scheduler.edit(sr->nextSearchStep, scheduler.time());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}, onExpired),
|
||||
next_refresh_time
|
||||
};
|
||||
} else {
|
||||
@@ -569,33 +591,30 @@ Dht::searchSynchedNodeListen(const Sp<Search>& sr, SearchNode& n)
|
||||
std::weak_ptr<Search> ws = sr;
|
||||
for (const auto& l : sr->listeners) {
|
||||
const auto& query = l.second.query;
|
||||
auto list_token = l.first;
|
||||
if (n.getListenTime(query, listenExp) > scheduler.time())
|
||||
|
||||
auto r = n.listenStatus.find(query);
|
||||
if (n.getListenTime(r, listenExp) > scheduler.time())
|
||||
continue;
|
||||
// if (logger_)
|
||||
// logger_->d(sr->id, n.node->id, "[search %s] [node %s] sending 'listen'",
|
||||
// sr->id.toString().c_str(), n.node->toString().c_str());
|
||||
|
||||
auto r = n.listenStatus.find(query);
|
||||
if (r == n.listenStatus.end()) {
|
||||
r = n.listenStatus.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(query),
|
||||
std::forward_as_tuple(
|
||||
[ws,list_token](const std::vector<Sp<Value>>& values, bool expired){
|
||||
if (auto sr = ws.lock()) {
|
||||
auto l = sr->listeners.find(list_token);
|
||||
if (l != sr->listeners.end()) {
|
||||
l->second.get_cb(values, expired);
|
||||
l.second.get_cb,
|
||||
l.second.sync_cb,
|
||||
n.node->openSocket([this,ws,query](const Sp<Node>& node, net::RequestAnswer&& answer) mutable {
|
||||
/* on new values */
|
||||
if (auto sr = ws.lock()) {
|
||||
scheduler.edit(sr->nextSearchStep, scheduler.time());
|
||||
sr->insertNode(node, scheduler.time(), answer.ntoken);
|
||||
if (auto sn = sr->getNode(node)) {
|
||||
sn->onValues(query, std::move(answer), types, scheduler);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [ws,list_token] (ListenSyncStatus status) {
|
||||
if (auto sr = ws.lock()) {
|
||||
auto l = sr->listeners.find(list_token);
|
||||
if (l != sr->listeners.end()) {
|
||||
l->second.sync_cb(status);
|
||||
}
|
||||
}
|
||||
})).first;
|
||||
}))).first;
|
||||
r->second.cacheExpirationJob = scheduler.add(time_point::max(), [this,ws,query,node=n.node]{
|
||||
if (auto sr = ws.lock()) {
|
||||
if (auto sn = sr->getNode(node)) {
|
||||
@@ -604,8 +623,7 @@ Dht::searchSynchedNodeListen(const Sp<Search>& sr, SearchNode& n)
|
||||
}
|
||||
});
|
||||
}
|
||||
auto prev_req = r != n.listenStatus.end() ? r->second.req : nullptr;
|
||||
auto new_req = network_engine.sendListen(n.node, sr->id, *query, n.token, prev_req,
|
||||
auto new_req = network_engine.sendListen(n.node, sr->id, *query, n.token, r->second.socketId,
|
||||
[this,ws,query](const net::Request& req, net::RequestAnswer&& answer) mutable
|
||||
{ /* on done */
|
||||
if (auto sr = ws.lock()) {
|
||||
@@ -625,16 +643,6 @@ Dht::searchSynchedNodeListen(const Sp<Search>& sr, SearchNode& n)
|
||||
if (auto sn = sr->getNode(req.node))
|
||||
sn->listenStatus.erase(query);
|
||||
}
|
||||
},
|
||||
[this,ws,query](const Sp<Node>& node, net::RequestAnswer&& answer) mutable
|
||||
{ /* on new values */
|
||||
if (auto sr = ws.lock()) {
|
||||
scheduler.edit(sr->nextSearchStep, scheduler.time());
|
||||
sr->insertNode(node, scheduler.time(), answer.ntoken);
|
||||
if (auto sn = sr->getNode(node)) {
|
||||
sn->onValues(query, std::move(answer), types, scheduler);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
// Here the request may have failed and the CachedListenStatus removed
|
||||
@@ -2175,7 +2183,6 @@ Dht::onError(Sp<net::Request> req, net::DhtProtocolException e) {
|
||||
if (logger_)
|
||||
logger_->e(node->id, "[node %s] token flush", node->toString().c_str());
|
||||
node->authError();
|
||||
node->cancelRequest(req);
|
||||
for (auto& srp : searches(node->getFamily())) {
|
||||
auto& sr = srp.second;
|
||||
for (auto& n : sr->nodes) {
|
||||
|
||||
+31
-11
@@ -76,7 +76,7 @@ Connection::Connection(asio::io_context& ctx, const bool ssl, std::shared_ptr<dh
|
||||
: id_(Connection::ids_++), ctx_(ctx), istream_(&read_buf_), logger_(l)
|
||||
{
|
||||
if (ssl){
|
||||
ssl_ctx_ = std::make_shared<asio::ssl::context>(asio::ssl::context::sslv23);
|
||||
ssl_ctx_ = std::make_shared<asio::ssl::context>(asio::ssl::context::tls_client);
|
||||
ssl_ctx_->set_default_verify_paths();
|
||||
ssl_ctx_->set_verify_mode(asio::ssl::verify_none);
|
||||
ssl_socket_ = std::make_unique<ssl_socket_t>(ctx_, ssl_ctx_);
|
||||
@@ -94,7 +94,7 @@ 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::sslv23);
|
||||
ssl_ctx_ = std::make_shared<asio::ssl::context>(asio::ssl::context::tls_client);
|
||||
ssl_ctx_->set_default_verify_paths();
|
||||
asio::error_code ec;
|
||||
if (server_ca){
|
||||
@@ -160,15 +160,13 @@ Connection::is_ssl() const
|
||||
}
|
||||
|
||||
void
|
||||
Connection::set_ssl_verification(const asio::ip::tcp::endpoint& endpoint, const asio::ssl::verify_mode verify_mode)
|
||||
Connection::set_ssl_verification(const std::string& hostname, const asio::ssl::verify_mode verify_mode)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (ssl_socket_ and verify_mode != asio::ssl::verify_none) {
|
||||
ssl_socket_->asio_ssl_stream().set_verify_mode(verify_mode);
|
||||
ssl_socket_->asio_ssl_stream().set_verify_callback([
|
||||
id = id_,
|
||||
logger = logger_,
|
||||
hostname = endpoint.address().to_string()
|
||||
id = id_, logger = logger_, hostname
|
||||
] (bool preverified, asio::ssl::verify_context& ctx) -> bool {
|
||||
if (logger)
|
||||
logger->d("[connection:%i] verify %s compliance to RFC 2818", id, hostname.c_str());
|
||||
@@ -483,7 +481,29 @@ Request::Request(asio::io_context& ctx, const std::string& url, const Json::Valu
|
||||
logger_->e("[http:request:%i] can't parse response to json", id_, err.c_str());
|
||||
}
|
||||
if (jsoncb)
|
||||
jsoncb(std::move(json), response.status_code);
|
||||
jsoncb(std::move(json), response);
|
||||
});
|
||||
}
|
||||
|
||||
Request::Request(asio::io_context& ctx, const std::string& url, OnJsonCb jsoncb, std::shared_ptr<dht::Logger> logger)
|
||||
: logger_(std::move(logger)), id_(Request::ids_++), ctx_(ctx),
|
||||
resolver_(std::make_shared<Resolver>(ctx, url, logger))
|
||||
{
|
||||
init_default_headers();
|
||||
set_header_field(restinio::http_field_t::accept, HTTP_HEADER_CONTENT_TYPE_JSON);
|
||||
Json::StreamWriterBuilder wbuilder;
|
||||
set_method(restinio::http_method_get());
|
||||
add_on_done_callback([this, jsoncb](const Response& response){
|
||||
Json::Value json;
|
||||
if (response.status_code != 0) {
|
||||
std::string err;
|
||||
Json::CharReaderBuilder rbuilder;
|
||||
auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
|
||||
if (!reader->parse(response.body.data(), response.body.data() + response.body.size(), &json, &err) and logger_)
|
||||
logger_->e("[http:request:%i] can't parse response to json", id_, err.c_str());
|
||||
}
|
||||
if (jsoncb)
|
||||
jsoncb(std::move(json), response);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -762,8 +782,8 @@ Request::connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, HandlerCb cb)
|
||||
eps.append(endpoint.address().to_string() + ":" + std::to_string(endpoint.port()) + " ");
|
||||
logger_->d("[http:request:%i] connect begin: %s", id_, eps.c_str());
|
||||
}
|
||||
if (get_url().protocol == "https"){
|
||||
if (server_ca_)
|
||||
if (get_url().protocol == "https") {
|
||||
if (server_ca_ or client_identity_.first)
|
||||
conn_ = std::make_shared<Connection>(ctx_, server_ca_, client_identity_, logger_);
|
||||
else
|
||||
conn_ = std::make_shared<Connection>(ctx_, true/*ssl*/, logger_);
|
||||
@@ -801,10 +821,10 @@ Request::connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, HandlerCb cb)
|
||||
|
||||
if (url.protocol == "https") {
|
||||
if (this_.server_ca_)
|
||||
this_.conn_->set_ssl_verification(endpoint, asio::ssl::verify_peer
|
||||
this_.conn_->set_ssl_verification(url.host, asio::ssl::verify_peer
|
||||
| asio::ssl::verify_fail_if_no_peer_cert);
|
||||
|
||||
if (this_.conn_ and this_.conn_->is_open() and this_.conn_->is_ssl()){
|
||||
if (this_.conn_ and this_.conn_->is_open() and this_.conn_->is_ssl()) {
|
||||
this_.conn_->async_handshake([id = this_.id_, cb, logger = this_.logger_](const asio::error_code& ec){
|
||||
if (ec == asio::error::operation_aborted)
|
||||
return;
|
||||
|
||||
+8
-22
@@ -560,7 +560,8 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
|
||||
{
|
||||
req->last_try = time_point::min();
|
||||
req->reply_time = time_point::min();
|
||||
onError(req, DhtProtocolException {msg->error_code});
|
||||
if (not req->setError(DhtProtocolException {msg->error_code}))
|
||||
onError(req, DhtProtocolException {msg->error_code});
|
||||
} else {
|
||||
if (logIncoming_)
|
||||
if (logger_)
|
||||
@@ -1072,27 +1073,11 @@ NetworkEngine::sendListen(Sp<Node> n,
|
||||
const InfoHash& hash,
|
||||
const Query& query,
|
||||
const Blob& token,
|
||||
Sp<Request> previous,
|
||||
Tid socketId,
|
||||
RequestCb&& on_done,
|
||||
RequestExpiredCb&& on_expired,
|
||||
SocketCb&& socket_cb)
|
||||
RequestExpiredCb&& on_expired)
|
||||
{
|
||||
Tid socket;
|
||||
Tid tid (n->getNewTid());
|
||||
if (previous and previous->node == n) {
|
||||
socket = previous->getSocket();
|
||||
} else {
|
||||
if (previous)
|
||||
if (logger_)
|
||||
logger_->e(hash, "[node %s] trying refresh listen contract with wrong node", previous->node->toString().c_str());
|
||||
socket = n->openSocket(std::move(socket_cb));
|
||||
}
|
||||
|
||||
if (not socket) {
|
||||
if (logger_)
|
||||
logger_->e(hash, "[node %s] unable to get a valid socket for listen. Aborting listen", n->toString().c_str());
|
||||
return {};
|
||||
}
|
||||
msgpack::sbuffer buffer;
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack_map(5+(config.network?1:0));
|
||||
@@ -1103,7 +1088,7 @@ NetworkEngine::sendListen(Sp<Node> n,
|
||||
pk.pack(KEY_VERSION); pk.pack(1);
|
||||
pk.pack(KEY_REQ_H); pk.pack(hash);
|
||||
pk.pack(KEY_REQ_TOKEN); packToken(pk, token);
|
||||
pk.pack(KEY_REQ_SID); pk.pack(socket);
|
||||
pk.pack(KEY_REQ_SID); pk.pack(socketId);
|
||||
if (has_query) {
|
||||
pk.pack(KEY_REQ_QUERY); pk.pack(query);
|
||||
}
|
||||
@@ -1125,8 +1110,7 @@ NetworkEngine::sendListen(Sp<Node> n,
|
||||
[=](const Request& req_status, bool done) { /* on expired */
|
||||
if (on_expired)
|
||||
on_expired(req_status, done);
|
||||
},
|
||||
socket
|
||||
}
|
||||
);
|
||||
sendRequest(req);
|
||||
++out_stats.listen;
|
||||
@@ -1263,6 +1247,7 @@ NetworkEngine::sendRefreshValue(Sp<Node> n,
|
||||
const Value::Id& vid,
|
||||
const Blob& token,
|
||||
RequestCb&& on_done,
|
||||
RequestErrorCb&& on_error,
|
||||
RequestExpiredCb&& on_expired)
|
||||
{
|
||||
Tid tid (n->getNewTid());
|
||||
@@ -1298,6 +1283,7 @@ NetworkEngine::sendRefreshValue(Sp<Node> n,
|
||||
}
|
||||
}
|
||||
},
|
||||
on_error,
|
||||
[=](const Request& req_status, bool done) { /* on expired */
|
||||
if (on_expired) {
|
||||
on_expired(req_status, done);
|
||||
|
||||
@@ -116,7 +116,6 @@ Node::cancelRequest(const Sp<net::Request>& req)
|
||||
{
|
||||
if (req) {
|
||||
req->cancel();
|
||||
closeSocket(req->closeSocket());
|
||||
requests_.erase(req->getTid());
|
||||
}
|
||||
}
|
||||
|
||||
+21
-7
@@ -27,6 +27,7 @@ struct Node;
|
||||
namespace net {
|
||||
|
||||
class NetworkEngine;
|
||||
class DhtProtocolException;
|
||||
struct ParsedMessage;
|
||||
|
||||
/*!
|
||||
@@ -72,16 +73,19 @@ struct Request {
|
||||
Sp<Node> node,
|
||||
Blob&& msg,
|
||||
std::function<void(const Request&, ParsedMessage&&)> on_done,
|
||||
std::function<void(const Request&, bool)> on_expired,
|
||||
Tid socket = 0) :
|
||||
node(node), tid(tid), type(type), on_done(on_done), on_expired(on_expired), msg(std::move(msg)), socket(socket) { }
|
||||
std::function<void(const Request&, bool)> on_expired) :
|
||||
node(node), tid(tid), type(type), on_done(on_done), on_expired(on_expired), msg(std::move(msg)) { }
|
||||
Request(MessageType type, Tid tid,
|
||||
Sp<Node> node,
|
||||
Blob&& msg,
|
||||
std::function<void(const Request&, ParsedMessage&&)> on_done,
|
||||
std::function<bool(const Request&, DhtProtocolException&&)> on_error,
|
||||
std::function<void(const Request&, bool)> on_expired) :
|
||||
node(node), tid(tid), type(type), on_done(on_done), on_error(on_error), on_expired(on_expired), msg(std::move(msg)) { }
|
||||
|
||||
Tid getTid() const { return tid; }
|
||||
MessageType getType() const { return type; }
|
||||
|
||||
Tid getSocket() { return socket; }
|
||||
Tid closeSocket() { auto ret = socket; socket = 0; return ret; }
|
||||
|
||||
void setExpired() {
|
||||
if (pending()) {
|
||||
state_ = Request::State::EXPIRED;
|
||||
@@ -96,6 +100,15 @@ struct Request {
|
||||
clear();
|
||||
}
|
||||
}
|
||||
bool setError(DhtProtocolException&& e) {
|
||||
if (pending()) {
|
||||
state_ = Request::State::EXPIRED;
|
||||
bool handled = on_error and on_error(*this, std::forward<DhtProtocolException>(e));
|
||||
clear();
|
||||
return handled;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void cancel() {
|
||||
if (pending()) {
|
||||
@@ -113,6 +126,7 @@ private:
|
||||
|
||||
void clear() {
|
||||
on_done = {};
|
||||
on_error = {};
|
||||
on_expired = {};
|
||||
msg = {};
|
||||
parts = {};
|
||||
@@ -128,11 +142,11 @@ private:
|
||||
time_point last_try {time_point::min()}; /* time of the last attempt to process the request. */
|
||||
|
||||
std::function<void(const Request&, ParsedMessage&&)> on_done {};
|
||||
std::function<bool(const Request&, DhtProtocolException&&)> on_error {};
|
||||
std::function<void(const Request&, bool)> on_expired {};
|
||||
|
||||
Blob msg {}; /* the serialized message. */
|
||||
std::vector<Blob> parts;
|
||||
Tid socket; /* the socket used for further reponses. */
|
||||
};
|
||||
|
||||
} /* namespace net */
|
||||
|
||||
+13
-5
@@ -65,10 +65,16 @@ struct Dht::SearchNode {
|
||||
ValueCache cache;
|
||||
Sp<Scheduler::Job> cacheExpirationJob {};
|
||||
Sp<net::Request> req {};
|
||||
CachedListenStatus(ValueStateCallback&& cb, SyncCallback&& scb)
|
||||
: cache(std::forward<ValueStateCallback>(cb), std::forward<SyncCallback>(scb)) {}
|
||||
Tid socketId {0};
|
||||
CachedListenStatus(ValueStateCallback&& cb, SyncCallback scb, Tid sid)
|
||||
: cache(std::forward<ValueStateCallback>(cb), std::forward<SyncCallback>(scb)), socketId(sid) {}
|
||||
CachedListenStatus(CachedListenStatus&&) = delete;
|
||||
CachedListenStatus(const CachedListenStatus&) = delete;
|
||||
~CachedListenStatus() {
|
||||
if (socketId and req and req->node) {
|
||||
req->node->closeSocket(socketId);
|
||||
}
|
||||
}
|
||||
};
|
||||
using NodeListenerStatus = std::map<Sp<Query>, CachedListenStatus>;
|
||||
|
||||
@@ -344,13 +350,15 @@ struct Dht::SearchNode {
|
||||
* Assuming the node is synced, should the "listen" request with Query q be
|
||||
* sent to this node now ?
|
||||
*/
|
||||
time_point getListenTime(const Sp<Query>& q, duration listen_expire) const {
|
||||
auto listen_status = listenStatus.find(q);
|
||||
if (listen_status == listenStatus.end() or not listen_status->second.req)
|
||||
time_point getListenTime(const decltype(listenStatus)::const_iterator listen_status, duration listen_expire) const {
|
||||
if (listen_status == listenStatus.cend() or not listen_status->second.req)
|
||||
return time_point::min();
|
||||
return listen_status->second.req->pending() ? time_point::max() :
|
||||
listen_status->second.req->reply_time + listen_expire - REANNOUNCE_MARGIN;
|
||||
}
|
||||
time_point getListenTime(const Sp<Query>& q, duration listen_expire) const {
|
||||
return getListenTime(listenStatus.find(q), listen_expire);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this node expired or candidate
|
||||
|
||||
@@ -107,7 +107,6 @@ ThreadPool::run(std::function<void()>&& cb)
|
||||
tasks_.emplace(std::move(cb));
|
||||
|
||||
// notify thread
|
||||
l.unlock();
|
||||
cv_.notify_one();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -135,6 +136,31 @@ CryptoTester::testCertificateRequest()
|
||||
CPPUNIT_ASSERT_MESSAGE(v.toString(), v);
|
||||
}
|
||||
|
||||
void CryptoTester::testCertificateSerialNumber()
|
||||
{
|
||||
static const std::string cert_pem = "-----BEGIN CERTIFICATE-----"
|
||||
"MIICDjCCAZSgAwIBAgIIS90uAKp+u/swCgYIKoZIzj0EAwMwTDEQMA4GA1UEAxMH"
|
||||
"ZGh0bm9kZTE4MDYGCgmSJomT8ixkAQETKDBlNDQxZTA4YWJmYTQzYTc3ZTVjZDBm"
|
||||
"Y2QzMzAzMTc4MjYxMTk0MzIwHhcNMTkxMTA3MDA0MTMwWhcNMjkxMTA0MDA0MTMw"
|
||||
"WjBMMRAwDgYDVQQDEwdkaHRub2RlMTgwNgYKCZImiZPyLGQBARMoMGU0NDFlMDhh"
|
||||
"YmZhNDNhNzdlNWNkMGZjZDMzMDMxNzgyNjExOTQzMjB2MBAGByqGSM49AgEGBSuB"
|
||||
"BAAiA2IABCZ7sBp0Pu+b5yIifoNXchU9crv9won0in++COWynvM4GCLF2Gk6QGhh"
|
||||
"YLDxNGsyQjGR7z5AGibvYhNLU0JA4RbmxYWHw4g3wBrPA1jm9hGZ8y5Y8R97d0Hl"
|
||||
"VpyreEMjRKNDMEEwHQYDVR0OBBYEFA5EHgir+kOnflzQ/NMwMXgmEZQyMA8GA1Ud"
|
||||
"EwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcGADAKBggqhkjOPQQDAwNoADBlAjEA"
|
||||
"kKF/6WReNytwSrJ8JSTToc7xWS5SvAa23Fnla4mywZUxUFS4VSxCMQTjQCknO3iZ"
|
||||
"AjBgxXyXYqn0d7vz7S6oAY5TdaD5YFT5MD2c1MAAp8pxQSwdPa9k0ZSoGIEn31Z0"
|
||||
"GxU="
|
||||
"-----END CERTIFICATE-----";
|
||||
/*
|
||||
* $ openssl x509 -in cert.pem -noout -serial
|
||||
* serial=4BDD2E00AA7EBBFB
|
||||
*/
|
||||
static constexpr std::array<uint8_t, 8> SERIAL {{0x4b,0xdd,0x2e,0x00,0xaa,0x7e,0xbb,0xfb}};
|
||||
auto serial = dht::crypto::Certificate(cert_pem).getSerialNumber();
|
||||
CPPUNIT_ASSERT(std::equal(SERIAL.begin(), SERIAL.end(), serial.begin(), serial.end()));
|
||||
}
|
||||
|
||||
void
|
||||
CryptoTester::tearDown() {
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -30,6 +31,7 @@ class CryptoTester : public CppUnit::TestFixture {
|
||||
CPPUNIT_TEST(testSignatureEncryption);
|
||||
CPPUNIT_TEST(testCertificateRevocation);
|
||||
CPPUNIT_TEST(testCertificateRequest);
|
||||
CPPUNIT_TEST(testCertificateSerialNumber);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
@@ -53,6 +55,10 @@ class CryptoTester : public CppUnit::TestFixture {
|
||||
* Test certificate requests
|
||||
*/
|
||||
void testCertificateRequest();
|
||||
/**
|
||||
* Test certificate serial number extraction
|
||||
*/
|
||||
void testCertificateSerialNumber();
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
Reference in new issue
Block a user