Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify TSL parsing #603

Merged
merged 1 commit into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 22 additions & 22 deletions src/crypto/Connect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
#include <zlib.h>

#include <algorithm>
#include <cstring>
#include <thread>

#ifdef _WIN32
Expand All @@ -57,9 +56,22 @@ using namespace std;
throw ex; \
}

Connect::Connect(const string &_url, const string &method, int timeout, const vector<X509Cert> &certs)
: _method(method)
, _timeout(timeout)
#if OPENSSL_VERSION_NUMBER < 0x30000000L
int BIO_socket_wait(int fd, bool read, time_t timeout)
{
fd_set confds;
FD_ZERO(&confds);
FD_SET(fd, &confds);
timeval tv { timeout, 0 };
return select(fd + 1, read ? &confds : nullptr, read ? nullptr : &confds, nullptr, &tv);
}
#endif



Connect::Connect(const string &_url, string _method, int _timeout, const vector<X509Cert> &certs)
: method(std::move(_method))
, timeout(_timeout)
{
DEBUG("Connecting to URL: %s", _url.c_str());
char *_host = nullptr, *_port = nullptr, *_path = nullptr;
Expand All @@ -74,7 +86,7 @@ Connect::Connect(const string &_url, const string &method, int timeout, const ve
string host = _host ? _host : "";
string port = _port ? _port : "80";
string path = _path ? _path : "/";
string url = (_path && strlen(_path) == 1 && _path[0] == '/' && _url[_url.size() - 1] != '/') ? _url + "/" : _url;
string url = (_path && char_traits<char>::length(_path) == 1 && _path[0] == '/' && _url[_url.size() - 1] != '/') ? _url + '/' : _url;
OPENSSL_free(_host);
OPENSSL_free(_port);
OPENSSL_free(_path);
Expand Down Expand Up @@ -167,9 +179,9 @@ Connect::Connect(const string &_url, const string &method, int timeout, const ve
}
}

fd = BIO_get_fd(d, nullptr);
if(_timeout > 0)
waitReadWrite(false);
if(int fd = BIO_get_fd(d, nullptr);
_timeout > 0 && BIO_socket_wait(fd, BIO_should_read(d), _timeout) == -1)
DEBUG("select failed");

BIO_printf(d, "%s %s HTTP/1.1\r\n", method.c_str(), path.c_str());
addHeader("Connection", "close");
Expand Down Expand Up @@ -272,7 +284,7 @@ Connect::Result Connect::exec(initializer_list<pair<string_view,string_view>> he
break;
}
auto end = chrono::high_resolution_clock::now();
if(_timeout > 0 && _timeout < chrono::duration_cast<chrono::seconds>(end - start).count())
if(timeout > 0 && timeout < chrono::duration_cast<chrono::seconds>(end - start).count())
break;
} while(rc != 0);
r.content.resize(pos);
Expand Down Expand Up @@ -322,7 +334,7 @@ Connect::Result Connect::exec(initializer_list<pair<string_view,string_view>> he
if(!r.isRedirect() || recursive > 3)
return r;
string url = r.headers["Location"].find("://") != string::npos ? r.headers["Location"] : baseurl + r.headers["Location"];
Connect c(url, _method, _timeout);
Connect c(url, method, timeout);
c.recursive = recursive + 1;
return c.exec(headers);
}
Expand All @@ -342,15 +354,3 @@ void Connect::sendProxyAuth()
BIO_pop(b64.get());
BIO_printf(d, "\r\n");
}

void Connect::waitReadWrite(bool read) const
{
if(fd < 0)
return;
fd_set confds;
FD_ZERO(&confds);
FD_SET(fd, &confds);
timeval tv { _timeout, 0 };
if(select(fd + 1, read ? &confds : nullptr, read ? nullptr : &confds, nullptr, &tv) == -1)
DEBUG("select failed");
}
25 changes: 12 additions & 13 deletions src/crypto/Connect.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,29 +37,30 @@ class Connect
struct Result {
std::string result, content;
std::map<std::string,std::string> headers;
bool operator !() const
operator bool() const noexcept
{
return !isOK();
return isOK();
}
bool isStatusCode(const std::string &code) const
template<class T>
inline bool isStatusCode(T code) const noexcept
{
return result.find(code) != std::string::npos;
return result.find(std::forward<T>(code)) != std::string::npos;
}
bool isOK() const
bool isOK() const noexcept
{
return isStatusCode("200");
}
bool isRedirect() const
bool isRedirect() const noexcept
{
return isStatusCode("301") || isStatusCode("302");
}
bool isForbidden() const
bool isForbidden() const noexcept
{
return isStatusCode("403");
}
};

Connect(const std::string &url, const std::string &method = "POST",
Connect(const std::string &url, std::string method = "POST",
int timeout = 0, const std::vector<X509Cert> &certs = {});
~Connect();
Result exec(std::initializer_list<std::pair<std::string_view,std::string_view>> headers,
Expand All @@ -73,15 +74,13 @@ class Connect
void addHeader(std::string_view key, std::string_view value);
void sendProxyAuth();
static std::string decompress(const std::string &encoding, const std::string &data) ;
void waitReadWrite(bool read) const;

std::string baseurl, _method;
std::string baseurl, method;
BIO *d = nullptr;
std::shared_ptr<SSL_CTX> ssl;
int _timeout;
int timeout;
bool doProxyConnect = false;
int fd = -1;
int recursive = 0;
int recursive = 0;
};

}
62 changes: 33 additions & 29 deletions src/crypto/TSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,20 @@ using namespace std;
using namespace xercesc;
using namespace xml_schema;

const set<string_view> TSL::SCHEMES_URI = {
namespace digidoc {

constexpr array SCHEMES_URI {
"http://uri.etsi.org/TrstSvc/eSigDir-1999-93-EC-TrustedList/TSLType/schemes",
"http://uri.etsi.org/TrstSvc/TrustedList/TSLType/EUlistofthelists",
};

const set<string_view> TSL::GENERIC_URI = {
constexpr array GENERIC_URI {
"http://uri.etsi.org/TrstSvc/eSigDir-1999-93-EC-TrustedList/TSLType/generic",
"http://uri.etsi.org/TrstSvc/TSLtype/generic/eSigDir-1999-93-EC-TrustedList",
"http://uri.etsi.org/TrstSvc/TrustedList/TSLType/EUgeneric",
};

const set<string_view> TSL::SERVICESTATUS_START = {
constexpr array SERVICESTATUS_START {
"http://uri.etsi.org/TrstSvc/eSigDir-1999-93-EC-TrustedList/Svcstatus/undersupervision",
//ts_119612v010201
"http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/undersupervision",
Expand All @@ -72,7 +74,7 @@ const set<string_view> TSL::SERVICESTATUS_START = {
"http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/recognisedatnationallevel",
};

const set<string_view> TSL::SERVICESTATUS_END = {
constexpr array SERVICESTATUS_END {
//ts_119612v010201
"http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/supervisionceased",
"http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/supervisionrevoked",
Expand All @@ -83,7 +85,7 @@ const set<string_view> TSL::SERVICESTATUS_END = {
"http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/deprecatedatnationallevel",
};

const set<string_view> TSL::SERVICES_SUPPORTED = {
constexpr array SERVICES_SUPPORTED {
"http://uri.etsi.org/TrstSvc/Svctype/CA/QC",
//"http://uri.etsi.org/TrstSvc/Svctype/CA/PKC", //???
//"http://uri.etsi.org/TrstSvc/Svctype/NationalRootCA-QC", //???
Expand All @@ -101,13 +103,15 @@ constexpr bool find(const C &list, const T &value)
return find(list.begin(), list.end(), value) != list.end();
}

}



TSL::TSL(string file)
: path(std::move(file))
{
try {
if(!File::fileExists(path))
if(path.empty() || File::fileSize(path) == 0)
return;
Properties properties;
properties.schema_location("http://uri.etsi.org/02231/v2#",
Expand Down Expand Up @@ -149,10 +153,10 @@ bool TSL::activate(const string &territory)
if(territory.size() != 2)
return false;
string cache = CONF(TSLCache);
string path = cache + "/" + territory + ".xml";
string path = cache + '/' + territory + ".xml";
if(File::fileExists(path))
return false;
ofstream(File::encodeName(path), ofstream::binary) << " ";
ofstream(File::encodeName(path), ofstream::binary) << ' ';
return true;
}

Expand All @@ -172,8 +176,7 @@ vector<TSL::Service> TSL::services() const
Service s;
s.type = serviceInfo.serviceTypeIdentifier();
s.name = toString(serviceInfo.serviceName());
time_t previousTime = 0;
if(!parseInfo(serviceInfo, s, previousTime))
if(!parseInfo(serviceInfo, s))
continue;
if(service.serviceHistory())
{
Expand All @@ -182,7 +185,7 @@ vector<TSL::Service> TSL::services() const
if(history.serviceTypeIdentifier() != serviceInfo.serviceTypeIdentifier())
DEBUG("History service type is not supported %s", history.serviceTypeIdentifier().c_str());
else
parseInfo(history, s, previousTime);
parseInfo(history, s);
}
}
services.push_back(std::move(s));
Expand Down Expand Up @@ -232,9 +235,9 @@ string TSL::nextUpdate() const
string() : date::to_string(tsl->schemeInformation().nextUpdate().dateTime().get());
}

string TSL::operatorName() const
string_view TSL::operatorName() const
{
return !tsl ? string() : toString(tsl->schemeInformation().schemeOperatorName());
return !tsl ? string_view() : toString(tsl->schemeInformation().schemeOperatorName());
}

vector<TSL::Service> TSL::parse()
Expand All @@ -257,7 +260,7 @@ vector<TSL::Service> TSL::parse(const string &url, const vector<X509Cert> &certs
vector< future< vector<TSL::Service> > > futures;
for(const TSL::Pointer &p: tsl.pointers())
{
if(!File::fileExists(cache + "/" + p.territory + ".xml"))
if(!File::fileExists(cache + '/' + p.territory + ".xml"))
continue;
futures.push_back(async(launch::async, [p, cache]{
return parse(p.location, p.certs, cache, p.territory + ".xml");
Expand Down Expand Up @@ -320,7 +323,7 @@ TSL TSL::parseTSL(const string &url, const vector<X509Cert> &certs,
ofstream(File::encodeName(path), ofstream::binary|fstream::trunc)
<< ifstream(File::encodeName(tmp), fstream::binary).rdbuf();
error_code ec;
std::filesystem::remove(std::filesystem::u8path(tmp), ec);
filesystem::remove(filesystem::u8path(tmp), ec);

ofstream(File::encodeName(path + ".etag"), ofstream::trunc) << etag;
DEBUG("TSL %s (%llu) signature is valid", territory.c_str(), tsl.sequenceNumber());
Expand All @@ -337,7 +340,7 @@ TSL TSL::parseTSL(const string &url, const vector<X509Cert> &certs,
}

template<class Info>
bool TSL::parseInfo(const Info &info, Service &s, time_t &previousTime)
bool TSL::parseInfo(const Info &info, Service &s)
{
vector<Qualifier> qualifiers;
if(info.serviceInformationExtensions())
Expand All @@ -347,7 +350,7 @@ bool TSL::parseInfo(const Info &info, Service &s, time_t &previousTime)
if(extension.critical())
{
if(extension.takenOverByType())
WARN("Found critical extension TakenOverByType '%s'", toString(extension.takenOverByType()->tSPName()).c_str());
WARN("Found critical extension TakenOverByType '%s'", toString(extension.takenOverByType()->tSPName()).data());
if(extension.expiredCertsRevocationInfo())
{
WARN("Found critical extension ExpiredCertsRevocationInfo");
Expand Down Expand Up @@ -417,10 +420,11 @@ bool TSL::parseInfo(const Info &info, Service &s, time_t &previousTime)
}

if(find(SERVICESTATUS_START, info.serviceStatus()))
s.validity.push_back({date::xsd2time_t(info.statusStartingTime()), previousTime, std::move(qualifiers)});
else if(!find(SERVICESTATUS_END, info.serviceStatus()))
s.validity.emplace(date::xsd2time_t(info.statusStartingTime()), std::move(qualifiers));
else if(find(SERVICESTATUS_END, info.serviceStatus()))
s.validity.emplace(date::xsd2time_t(info.statusStartingTime()), nullopt);
else
DEBUG("Unknown service status %s", info.serviceStatus().c_str());
previousTime = date::xsd2time_t(info.statusStartingTime());
return true;
}

Expand Down Expand Up @@ -462,16 +466,16 @@ vector<TSL::Pointer> TSL::pointers() const
return pointer;
}

unsigned long long TSL::sequenceNumber() const
unsigned long long TSL::sequenceNumber() const
{
return !tsl ? 0 : tsl->schemeInformation().tSLSequenceNumber();
}

vector<X509Cert> TSL::serviceDigitalIdentities(const tsl::OtherTSLPointerType &other, string_view region)
{
if(!other.serviceDigitalIdentities())
return {};
vector<X509Cert> result;
if(!other.serviceDigitalIdentities())
return result;
for(const auto &service: other.serviceDigitalIdentities()->serviceDigitalIdentity())
{
for(const auto &digitalID: service.digitalId())
Expand Down Expand Up @@ -509,9 +513,9 @@ X509Cert TSL::signingCert() const

vector<X509Cert> TSL::signingCerts() const
{
if(!tsl || !tsl->schemeInformation().pointersToOtherTSL())
return {};
vector<X509Cert> result;
if(!tsl || !tsl->schemeInformation().pointersToOtherTSL())
return result;
for(const auto &other: tsl->schemeInformation().pointersToOtherTSL()->otherTSLPointer())
{
vector<X509Cert> certs = serviceDigitalIdentities(other, "pivot");
Expand All @@ -526,17 +530,17 @@ string TSL::territory() const
string() : tsl->schemeInformation().schemeTerritory().get();
}

string TSL::toString(const InternationalNamesType &obj, string_view lang)
string_view TSL::toString(const InternationalNamesType &obj, string_view lang)
{
for(const InternationalNamesType::NameType &name: obj.name())
if(name.lang() == lang)
return name;
return obj.name().front();
}

string TSL::type() const
string_view TSL::type() const
{
return !tsl ? string() : tsl->schemeInformation().tSLType();
return !tsl ? string_view() : tsl->schemeInformation().tSLType();
}

string TSL::url() const
Expand Down Expand Up @@ -681,7 +685,7 @@ bool TSL::validateRemoteDigest(const string &url)

vector<unsigned char> digest;
if(r.content.size() == 32)
digest.assign(r.content.c_str(), r.content.c_str() + r.content.size());
digest.assign(r.content.cbegin(), r.content.cend());
else
{
r.content.erase(r.content.find_last_not_of(" \n\r\t") + 1);
Expand Down
Loading