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

Allow only qualified OCSP-s #645

Merged
merged 1 commit into from
Nov 27, 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
16 changes: 4 additions & 12 deletions src/crypto/TSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
#include "Conf.h"
#include "XMLDocument.h"
#include "crypto/Connect.h"
#include "util/algorithm.h"
#include "util/DateTime.h"
#include "util/File.h"

#include <algorithm>
#include <array>
#include <charconv>
#include <fstream>
Expand Down Expand Up @@ -80,18 +80,10 @@ constexpr array SERVICESTATUS_END {

constexpr array SERVICES_SUPPORTED {
"http://uri.etsi.org/TrstSvc/Svctype/CA/QC",
"http://uri.etsi.org/TrstSvc/Svctype/Certstatus/OCSP",
"http://uri.etsi.org/TrstSvc/Svctype/Certstatus/OCSP/QC",
"http://uri.etsi.org/TrstSvc/Svctype/TSA/QTST",
};

template<typename C, typename T>
[[nodiscard]]
constexpr bool contains(const C &list, const T &value)
{
return find(list.begin(), list.end(), value) != list.end();
}

}


Expand Down Expand Up @@ -212,6 +204,7 @@ vector<TSL::Service> TSL::parse()
vector<TSL::Service> TSL::parse(const string &url, const vector<X509Cert> &certs,
const string &cache, const string &territory)
{
vector<Service> list;
try {
TSL tsl = parseTSL(url, certs, cache, territory);
if(tsl.pointers().empty())
Expand All @@ -226,20 +219,19 @@ vector<TSL::Service> TSL::parse(const string &url, const vector<X509Cert> &certs
return parse(p.location, p.certs, cache, p.territory + ".xml");
}));
}
vector<Service> list;
for(auto &f: futures)
{
vector<Service> services = f.get();
list.insert(list.end(), make_move_iterator(services.begin()), make_move_iterator(services.end()));
}
return list;
}
catch(const Exception &e)
{
debugException(e);
ERR("TSL %s Failed to validate list", territory.c_str());
return {};
list.clear();
}
return list;
}

TSL TSL::parseTSL(const string &url, const vector<X509Cert> &certs,
Expand Down
29 changes: 10 additions & 19 deletions src/crypto/X509CertStore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,17 @@
#include "crypto/Connect.h"
#include "crypto/OpenSSLHelpers.h"
#include "crypto/TSL.h"
#include "util/algorithm.h"
#include "util/DateTime.h"
#include "util/log.h"

#include <openssl/conf.h>
#include <openssl/ssl.h>
#include <openssl/x509v3.h>

#include <algorithm>

using namespace digidoc;
using namespace std;

template<typename C, typename T>
[[nodiscard]]
constexpr bool contains(const C &list, const T &value)
{
return find(list.begin(), list.end(), std::forward<decltype(value)>(value)) != list.end();
};

const X509CertStore::Type X509CertStore::CA {
"http://uri.etsi.org/TrstSvc/Svctype/CA/QC",
};
Expand All @@ -52,7 +44,6 @@ const X509CertStore::Type X509CertStore::TSA {

const X509CertStore::Type X509CertStore::OCSP {
"http://uri.etsi.org/TrstSvc/Svctype/CA/QC",
"http://uri.etsi.org/TrstSvc/Svctype/Certstatus/OCSP",
"http://uri.etsi.org/TrstSvc/Svctype/Certstatus/OCSP/QC",
};

Expand Down Expand Up @@ -181,7 +172,7 @@ int X509CertStore::validate(int ok, X509_STORE_CTX *ctx, const Type &type)
{
if(type.find(s.type) == type.cend())
continue;
if(none_of(s.certs.cbegin(), s.certs.cend(), [&](const X509Cert &issuer){
if(none_of(s.certs, [&](const X509Cert &issuer) {
if(issuer == x509)
return true;
if(X509_check_issued(issuer.handle(), x509) != X509_V_OK)
Expand Down Expand Up @@ -254,13 +245,13 @@ bool X509CertStore::verify(const X509Cert &cert, bool noqscd) const
bool isESeal = // Special treamtent for E-Seals
contains(policies, X509Cert::QCP_LEGAL) ||
contains(qcstatement, X509Cert::QCT_ESEAL);
auto matchPolicySet = [&policies](const vector<string> &policySet){
return all_of(policySet.cbegin(), policySet.cend(), [&policies](const string &policy) {
auto matchPolicySet = [&policies](const vector<string> &policySet) {
return all_of(policySet, [&policies](const string &policy) {
return contains(policies, policy);
});
};
auto matchKeyUsageSet = [&keyUsage](const map<X509Cert::KeyUsage,bool> &keyUsageSet){
return all_of(keyUsageSet.cbegin(), keyUsageSet.cend(), [&keyUsage](pair<X509Cert::KeyUsage, bool> keyUsageBit){
auto matchKeyUsageSet = [&keyUsage](const map<X509Cert::KeyUsage,bool> &keyUsageSet) {
return all_of(keyUsageSet, [&keyUsage](pair<X509Cert::KeyUsage, bool> keyUsageBit) {
return contains(keyUsage, keyUsageBit.first) == keyUsageBit.second;
});
};
Expand All @@ -269,14 +260,14 @@ bool X509CertStore::verify(const X509Cert &cert, bool noqscd) const
{
if(q.assert_ == "all")
{
if(!(all_of(q.policySet.cbegin(), q.policySet.cend(), matchPolicySet) &&
all_of(q.keyUsage.cbegin(), q.keyUsage.cend(), matchKeyUsageSet)))
if(!(all_of(q.policySet, matchPolicySet) &&
all_of(q.keyUsage, matchKeyUsageSet)))
continue;
}
else if(q.assert_ == "atLeastOne")
{
if(!(any_of(q.policySet.cbegin(), q.policySet.cend(), matchPolicySet) ||
any_of(q.keyUsage.cbegin(), q.keyUsage.cend(), matchKeyUsageSet)))
if(!(any_of(q.policySet, matchPolicySet) ||
any_of(q.keyUsage, matchKeyUsageSet)))
continue;
}
else
Expand Down
61 changes: 61 additions & 0 deletions src/util/algorithm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* libdigidocpp
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/

#pragma once

#include <algorithm>

namespace digidoc
{

template<typename C, typename P>
[[nodiscard]]
constexpr bool all_of(const C &list, P pred)
{
return std::all_of(list.begin(), list.end(), std::forward<P>(pred));
}

template<typename C, typename P>
[[nodiscard]]
constexpr bool any_of(const C &list, P pred)
{
return std::any_of(list.begin(), list.end(), std::forward<P>(pred));
}

template<typename C, typename T>
[[nodiscard]]
constexpr bool contains(const C &list, T value)
{
return std::find(list.begin(), list.end(), std::forward<T>(value)) != list.end();
}

template<typename C, typename P>
[[nodiscard]]
constexpr bool none_of(const C &list, P pred)
{
return std::none_of(list.begin(), list.end(), std::forward<P>(pred));
}

template<typename T>
[[nodiscard]]
constexpr bool starts_with(T str, T needle) {
return str.size() >= needle.size() && str.compare(0, needle.size(), needle) == 0;
}

}
84 changes: 24 additions & 60 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,64 +17,28 @@ add_test(NAME runtest
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/unittests --build_info=YES --report_level=no --logger=${TEST_FORMAT},all,${CMAKE_CURRENT_BINARY_DIR}/libdigidocpp.xml -- ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)
add_test(NAME TSLTest_CA-invalid-type
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/TSLTests -- EE_T-CA-invalid-type.xml bad ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)
add_test(NAME TSLTest_CA-non-qa
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/TSLTests -- EE_T-CA-non-qa.xml bad ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)
add_test(NAME TSLTest_CA-withdrawn
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/TSLTests -- EE_T-CA-withdrawn.xml bad ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)
add_test(NAME TSLTest_CA-withdrawn-granted-before
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/TSLTests -- EE_T-CA-withdrawn-granted-before.xml good ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)
add_test(NAME TSLTest_CA-withdrawn-granted-later
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/TSLTests -- EE_T-CA-withdrawn-granted-later.xml bad ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)
add_test(NAME TSLTest_OCSP-invalid-type
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/TSLTests -- EE_T-OCSP-invalid-type.xml bad ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)
add_test(NAME TSLTest_OCSP-withdrawn
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/TSLTests -- EE_T-OCSP-withdrawn.xml bad ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)
add_test(NAME TSLTest_OCSP-withdrawn-granted-before
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/TSLTests -- EE_T-OCSP-withdrawn-granted-before.xml good ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)
add_test(NAME TSLTest_OCSP-withdrawn-granted-later
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/TSLTests -- EE_T-OCSP-withdrawn-granted-later.xml bad ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)
add_test(NAME TSLTest_TSA-invalid-type
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/TSLTests -- EE_T-TSA-invalid-type.xml bad ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)
add_test(NAME TSLTest_TSA-withdrawn
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/TSLTests -- EE_T-TSA-withdrawn.xml bad ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)
add_test(NAME TSLTest_TSA-withdrawn-granted-before
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/TSLTests -- EE_T-TSA-withdrawn-granted-before.xml good ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)
add_test(NAME TSLTest_TSA-withdrawn-granted-later
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/TSLTests -- EE_T-TSA-withdrawn-granted-later.xml bad ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)
add_test(NAME TSLTest_EE_T-no_QCStatement
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/TSLTests -- EE_T-no_QCStatement.xml bad ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)
add_test(NAME TSLTest_EE_T-no_QCSD
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/TSLTests -- EE_T-no_QCSD.xml bad ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)

# Bad status tests
foreach(TEST CA-non-qa no_QCStatement no_QCSD
CA-invalid-type CA-withdrawn CA-granted-later CA-withdrawn-granted-later CA-noqscd-granted-later
OCSP-invalid-type OCSP-withdrawn OCSP-granted-later OCSP-withdrawn-granted-later OCSP-noqscd-granted-later
TSA-invalid-type TSA-withdrawn TSA-granted-later TSA-withdrawn-granted-later TSA-noqscd-granted-later
)
add_test(NAME TSLTest_${TEST}
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/TSLTests -- EE_T-${TEST}.xml bad ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)
endforeach()

# Good status tests
foreach(TEST CA-withdrawn-granted-before CA-noqscd-granted-before
OCSP-withdrawn-granted-before OCSP-noqscd-granted-before
TSA-withdrawn-granted-before TSA-noqscd-granted-before
)
add_test(NAME TSLTest_${TEST}
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/TSLTests -- EE_T-${TEST}.xml good ${CMAKE_CURRENT_SOURCE_DIR}/data
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src
)
endforeach()

add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS unittests TSLTests)
Loading
Loading