Skip to content

Commit

Permalink
Allow only qualified OCSP-s (#645)
Browse files Browse the repository at this point in the history
IB-8298

Signed-off-by: Raul Metsma <[email protected]>
  • Loading branch information
metsma authored Nov 27, 2024
1 parent f90a086 commit d4c5c5d
Show file tree
Hide file tree
Showing 14 changed files with 11,794 additions and 91 deletions.
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

0 comments on commit d4c5c5d

Please sign in to comment.