diff --git a/cmake b/cmake index 057c95e3..8ce75e60 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 057c95e365c9d018bd15afe0dc03ab4122b4147b +Subproject commit 8ce75e6057067ca51d7c619d34d88422bad201e5 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 874f4b45..86ccfd45 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -78,7 +78,6 @@ target_link_libraries(digidocpp_priv LibXml2::LibXml2 OpenSSL::SSL xmlsec - $<$:Ws2_32> ) add_library(digidocpp diff --git a/src/crypto/Connect.cpp b/src/crypto/Connect.cpp index d5b66718..9601d48c 100644 --- a/src/crypto/Connect.cpp +++ b/src/crypto/Connect.cpp @@ -173,7 +173,7 @@ Connect::Connect(const string &_url, string _method, int _timeout, const vector< } } -#if OPENSSL_VERSION_NUMBER > 0x30000000L +#if OPENSSL_VERSION_NUMBER < 0x30000000L if(_timeout > 0) { int fd = BIO_get_fd(d, nullptr); @@ -251,12 +251,6 @@ string Connect::decompress(const string &encoding, const string &data) return out; } -Connect::Result Connect::exec(initializer_list> headers, - const vector &data) -{ - return exec(headers, data.data(), data.size()); -} - Connect::Result Connect::exec(initializer_list> headers, const unsigned char *data, size_t size) { @@ -295,6 +289,10 @@ Connect::Result Connect::exec(initializer_list> he stringstream stream(r.content); string line; + auto to_lower = [](string str) { + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + return str; + }; while(getline(stream, line)) { line.resize(max(line.size() - 1, 0)); @@ -307,18 +305,17 @@ Connect::Result Connect::exec(initializer_list> he } size_t split = line.find(": "); if(split != string::npos) - r.headers[line.substr(0, split)] = line.substr(split + 2); + r.headers[to_lower(line.substr(0, split))] = line.substr(split + 2); else - r.headers[line] = string(); + r.headers[to_lower(line)] = string(); } pos = r.content.find("\r\n\r\n"); if(pos != string::npos) r.content.erase(0, pos + 4); - - const auto transfer_encoding = r.headers.find("Transfer-Encoding"); - if(transfer_encoding != r.headers.cend() && - transfer_encoding->second.find("chunked") != string::npos) { + if(const auto it = r.headers.find("transfer-encoding"); + it != r.headers.cend() && + it->second.find("chunked") != string::npos) { pos = 0; for(size_t chunkpos = r.content.find("\r\n", pos); chunkpos != string::npos; @@ -331,14 +328,14 @@ Connect::Result Connect::exec(initializer_list> he } } - const auto it = r.headers.find("Content-Encoding"); - if(it != r.headers.cend()) + if(const auto it = r.headers.find("content-encoding"); + it != r.headers.cend()) r.content = decompress(it->second, r.content); if(!r.isRedirect() || recursive > 3) return r; - string location = r.headers.find("Location") == r.headers.cend() ? r.headers["location"] : r.headers["Location"]; - string url = location.find("://") != string::npos ? location : baseurl + location; + string &location = r.headers["location"]; + string url = location.find("://") != string::npos ? std::move(location) : baseurl + location; Connect c(url, method, timeout); c.recursive = recursive + 1; return c.exec(headers); diff --git a/src/crypto/Connect.h b/src/crypto/Connect.h index 059ee672..c74f7301 100644 --- a/src/crypto/Connect.h +++ b/src/crypto/Connect.h @@ -63,8 +63,11 @@ class Connect Connect(const std::string &url, std::string method = "POST", int timeout = 0, const std::vector &certs = {}); ~Connect(); - Result exec(std::initializer_list> headers, - const std::vector &data); + inline Result exec(std::initializer_list> headers, + const std::vector &data) + { + return exec(headers, data.data(), data.size()); + } Result exec(std::initializer_list> headers = {}, const unsigned char *data = nullptr, size_t size = 0); diff --git a/src/crypto/TSL.cpp b/src/crypto/TSL.cpp index 266b28c8..68dbc742 100644 --- a/src/crypto/TSL.cpp +++ b/src/crypto/TSL.cpp @@ -100,11 +100,12 @@ constexpr bool contains(const C &list, const T &value) -TSL::TSL(const string &file) +TSL::TSL(string file) : XMLDocument(file, {"TrustServiceStatusList", TSL_NS}) , schemeInformation((*this)/"SchemeInformation") + , path(std::move(file)) { - if(file.empty()) + if(path.empty()) return; if(get()) { @@ -112,7 +113,7 @@ TSL::TSL(const string &file) xmlSecAddIDs(get(), nullptr, ids.data()); } else - WARN("Failed to parse configuration: %s", file.c_str()); + WARN("Failed to parse configuration: %s", path.c_str()); } bool TSL::activate(const string &territory) @@ -174,7 +175,7 @@ string TSL::fetch(const string &url, const string &path) if(!r || r.content.empty()) THROW("HTTP status code is not 200 or content is empty"); ofstream(File::encodeName(path), fstream::binary|fstream::trunc) << r.content; - return r.headers["ETag"]; + return r.headers["etag"]; } catch(const Exception &) { @@ -254,19 +255,19 @@ TSL TSL::parseTSL(const string &url, const vector &certs, TSL tsl(path); tsl.validate(certs); valid = std::move(tsl); - DEBUG("TSL %s (%llu) signature is valid", territory.c_str(), tsl.sequenceNumber()); + DEBUG("TSL %s (%llu) signature is valid", territory.c_str(), valid.sequenceNumber()); if(valid.isExpired()) { if(!CONF(TSLAutoUpdate) && CONF(TSLAllowExpired)) return valid; - THROW("TSL %s (%llu) is expired", territory.c_str(), tsl.sequenceNumber()); + THROW("TSL %s (%llu) is expired", territory.c_str(), valid.sequenceNumber()); } - if(CONF(TSLOnlineDigest) && (File::modifiedTime(path) < (time(nullptr) - (60 * 60 * 24)))) + if(CONF(TSLOnlineDigest) && (File::modifiedTime(valid.path) < (time(nullptr) - (60 * 60 * 24)))) { if(valid.validateETag(url)) - File::updateModifiedTime(path, time(nullptr)); + File::updateModifiedTime(valid.path, time(nullptr)); } return valid; @@ -279,17 +280,18 @@ TSL TSL::parseTSL(const string &url, const vector &certs, try { string tmp = path + ".tmp"; string etag = fetch(url, tmp); - TSL tsl = TSL(tmp); + TSL tsl = TSL(std::move(tmp)); tsl.validate(certs); valid = std::move(tsl); ofstream(File::encodeName(path), ofstream::binary|fstream::trunc) - << ifstream(File::encodeName(tmp), fstream::binary).rdbuf(); + << ifstream(File::encodeName(valid.path), fstream::binary).rdbuf(); error_code ec; - filesystem::remove(filesystem::u8path(tmp), ec); + filesystem::remove(filesystem::u8path(valid.path), ec); ofstream(File::encodeName(path + ".etag"), ofstream::trunc) << etag; - DEBUG("TSL %s (%llu) signature is valid", territory.c_str(), tsl.sequenceNumber()); + + DEBUG("TSL %s (%llu) signature is valid", territory.c_str(), valid.sequenceNumber()); } catch(const Exception &) { ERR("TSL %s signature is invalid", territory.c_str()); if(!valid) @@ -382,16 +384,11 @@ bool TSL::parseInfo(XMLNode info, Service &s) return true; } -string TSL::path() const -{ - return get() && get()->name ? string(get()->name) : string(); -} - vector TSL::pivotURLs() const { if(!*this) return {}; - auto current = File::fileName(path()); + auto current = File::fileName(path); if(size_t pos = current.find_first_of('.'); current.find("pivot") != string::npos && pos != string::npos) current = current.substr(0, pos); @@ -570,16 +567,15 @@ bool TSL::validateETag(const string &url) return false; } - auto it = r.headers.find("ETag"); + auto it = r.headers.find("etag"); if(it == r.headers.cend()) return validateRemoteDigest(url); DEBUG("Remote ETag: %s", it->second.c_str()); - ifstream is(File::encodeName(path() + ".etag")); + ifstream is(File::encodeName(path + ".etag")); if(!is.is_open()) THROW("Cached ETag does not exist"); - string etag(it->second.size(), 0); - is.read(etag.data(), streamsize(etag.size())); + string etag(istreambuf_iterator(is), {}); DEBUG("Cached ETag: %s", etag.c_str()); if(etag != it->second) THROW("Remote ETag does not match"); @@ -617,7 +613,7 @@ bool TSL::validateRemoteDigest(const string &url) Digest sha(URI_RSA_SHA256); array buf{}; - ifstream is(path(), ifstream::binary); + ifstream is(path, ifstream::binary); while(is) { is.read((char*)buf.data(), streamsize(buf.size())); diff --git a/src/crypto/TSL.h b/src/crypto/TSL.h index ac5029fe..629c584f 100644 --- a/src/crypto/TSL.h +++ b/src/crypto/TSL.h @@ -39,7 +39,7 @@ class TSL: private XMLDocument struct Service { std::vector certs; std::map validity; std::string type, additional, name; }; struct Pointer { std::string territory, location; std::vector certs; }; - TSL(const std::string &file = {}); + TSL(std::string file = {}); bool isExpired() const; void validate() const; void validate(const std::vector &certs, int recursion = 0) const; @@ -59,7 +59,6 @@ class TSL: private XMLDocument static std::vector parse(); private: - std::string path() const; std::vector pivotURLs() const; X509Cert signingCert() const; std::vector signingCerts() const; @@ -78,5 +77,6 @@ class TSL: private XMLDocument static std::string_view toString(XMLNode obj, std::string_view lang = "en") noexcept; XMLNode schemeInformation; + std::string path; }; }