Skip to content

Commit 0738ab6

Browse files
committed
Update tests for OpenSSL 4.0 compatibility
* add workaround for fedora disabled SHA-1 policy IB-8759 Signed-off-by: Raul Metsma <raul@metsma.ee>
1 parent 190a3a5 commit 0738ab6

45 files changed

Lines changed: 13853 additions & 1374 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/build.yml‎

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ jobs:
6464
sudo ln -s $PWD/cache/* /Library/
6565
cmake --preset ${{ matrix.target }} -DCMAKE_BUILD_TYPE=RelWithDebInfo
6666
cmake --build --preset ${{ matrix.target }}
67-
cmake --build --preset ${{ matrix.target }} --target test pkcs11sign embedlibs
67+
ctest --preset ${{ matrix.target }}
68+
cmake --build --preset ${{ matrix.target }} --target pkcs11sign embedlibs
6869
cmake --build --preset ${{ matrix.target }} --target zipdebug pkgbuild
6970
- name: Build ${{ matrix.target }}
7071
if: matrix.target != 'macos'
@@ -86,7 +87,7 @@ jobs:
8687
test -n "$UDID" || { echo "no available simulator"; exit 1; }
8788
xcrun simctl boot "$UDID"
8889
xcrun simctl bootstatus "$UDID" -b
89-
ctest --preset iphonesimulator --no-tests=error
90+
ctest --preset iphonesimulator
9091
- name: Archive artifacts
9192
uses: actions/upload-artifact@v7
9293
with:
@@ -134,35 +135,38 @@ jobs:
134135
fedora:
135136
name: Build on Fedora ${{ matrix.container }}
136137
runs-on: ubuntu-latest
138+
continue-on-error: ${{ matrix.container == 'rawhide' }}
137139
container: fedora:${{ matrix.container }}
138140
strategy:
139141
matrix:
140-
container: [43, 44, rawhide]
142+
container: [43, 44, 45, rawhide]
141143
steps:
142144
- name: Install Deps
143145
run: |
144146
dnf install -y --setopt=install_weak_deps=False \
145-
${FEDORA_DEPS} doxygen boost-test swig python3-devel java-25-openjdk-devel rpm-build
147+
${FEDORA_DEPS} ninja-build doxygen boost-devel swig python3-devel java-25-openjdk-devel rpm-build
146148
- name: Checkout
147149
uses: actions/checkout@v6
148150
- name: Build
149151
run: |
150-
cmake -DCMAKE_INSTALL_SYSCONFDIR=/etc -B build -S .
151-
cmake --build build
152-
cmake --build build --target package
152+
cmake --preset default -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_SYSCONFDIR=/etc
153+
cmake --build --preset default
154+
cmake --build --preset default --target package
155+
- name: Test
156+
run: ctest --preset default
153157
- name: Archive artifacts
154158
uses: actions/upload-artifact@v7
155159
with:
156160
name: fedora_${{ matrix.container }}
157-
path: build/*.rpm
161+
path: build/default/*.rpm
158162
ubuntu:
159163
name: Build on ${{ matrix.dist }} ${{ matrix.ver }} ${{ matrix.arch }}
160164
runs-on: ubuntu-24.04${{ matrix.arch == 'arm64' && '-arm' || '' }}
161165
container: ${{ matrix.dist }}:${{ matrix.ver }}
162166
strategy:
163167
matrix:
164168
dist: [ubuntu]
165-
ver: ['22.04', '24.04', '26.04']
169+
ver: ['22.04', '24.04', '26.04', '26.10']
166170
arch: [amd64, arm64]
167171
java: [17]
168172
include: [

‎CMakePresets.json‎

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"cacheVariables": {
4848
"CMAKE_DISABLE_FIND_PACKAGE_Boost": "YES",
4949
"CMAKE_DISABLE_FIND_PACKAGE_Doxygen": "YES",
50+
"CMAKE_FIND_ROOT_PATH": null,
5051
"BUILD_TOOLS": "NO",
5152
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
5253
}
@@ -134,6 +135,11 @@
134135
"name": "windows",
135136
"displayName": "Windows",
136137
"inherits": "base",
138+
"condition": {
139+
"type": "equals",
140+
"lhs": "${hostSystemName}",
141+
"rhs": "Windows"
142+
},
137143
"environment": {
138144
"BUILD_SUFFIX": "-$env{PLATFORM}"
139145
},
@@ -156,6 +162,10 @@
156162
}
157163
],
158164
"buildPresets": [
165+
{
166+
"name": "default",
167+
"configurePreset": "default"
168+
},
159169
{
160170
"name": "macos",
161171
"configurePreset": "macos"
@@ -197,25 +207,30 @@
197207
"testPresets":
198208
[
199209
{
200-
"name": "base",
201-
"hidden": true,
210+
"name": "default",
211+
"configurePreset": "default",
202212
"output": {
203213
"outputOnFailure": true
204214
},
205215
"execution": {
206216
"noTestsAction": "error"
207217
}
208218
},
219+
{
220+
"name": "macos",
221+
"configurePreset": "macos",
222+
"inherits": "default"
223+
},
209224
{
210225
"name": "iphonesimulator",
211226
"configurePreset": "iphonesimulator",
212-
"inherits": "base"
227+
"inherits": "default"
213228
},
214229
{
215230
"name": "windows-static",
216231
"configurePreset": "windows-static",
217232
"configuration": "RelWithDebInfo",
218-
"inherits": "base"
233+
"inherits": "default"
219234
}
220235
]
221236
}

‎debian/rules‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#!/usr/bin/make -f
2-
DEB_MAKE_CHECK_TARGET = test
32

43
%:
54
dh $@

‎src/Exports.h‎

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,10 @@
3333
#else
3434
#define DIGIDOCPP_DEPRECATED
3535
#endif
36-
#define DIGIDOCPP_WARNING_PUSH __pragma(warning(push))
37-
#define DIGIDOCPP_WARNING_POP __pragma(warning(pop))
38-
#define DIGIDOCPP_WARNING_DISABLE_CLANG(text)
39-
#define DIGIDOCPP_WARNING_DISABLE_GCC(text)
40-
#define DIGIDOCPP_WARNING_DISABLE_MSVC(number) __pragma(warning(disable: number))
4136
#pragma warning( disable: 4251 ) // shut up std::vector warnings
4237
#else
4338
#define DIGIDOCPP_EXPORT __attribute__ ((visibility("default")))
4439
#define DIGIDOCPP_DEPRECATED __attribute__ ((__deprecated__))
45-
#define DIGIDOCPP_DO_PRAGMA(text) _Pragma(#text)
46-
#define DIGIDOCPP_WARNING_PUSH DIGIDOCPP_DO_PRAGMA(GCC diagnostic push)
47-
#define DIGIDOCPP_WARNING_POP DIGIDOCPP_DO_PRAGMA(GCC diagnostic pop)
48-
#if __clang__
49-
#define DIGIDOCPP_WARNING_DISABLE_CLANG(text) DIGIDOCPP_DO_PRAGMA(clang diagnostic ignored text)
50-
#else
51-
#define DIGIDOCPP_WARNING_DISABLE_CLANG(text)
52-
#endif
53-
#define DIGIDOCPP_WARNING_DISABLE_GCC(text) DIGIDOCPP_DO_PRAGMA(GCC diagnostic ignored text)
54-
#define DIGIDOCPP_WARNING_DISABLE_MSVC(text)
5540
#endif
5641

5742
#define DISABLE_COPY(Class) \

‎src/crypto/OCSP.cpp‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,27 @@ void OCSP::verifyResponse(const X509Cert &cert, const vector<X509Cert> &untruste
216216
}
217217
auto store = X509CertStore::createStore(X509CertStore::OCSP, tm);
218218
ERR_clear_error();
219-
if(OCSP_basic_verify(basic.get(), stack.get(), store.get(), OCSP_NOCHECKS | OCSP_PARTIAL_CHAIN) != 1)
219+
int verified = OCSP_basic_verify(basic.get(), stack.get(), store.get(), OCSP_NOCHECKS | OCSP_PARTIAL_CHAIN);
220+
if(verified != 1)
221+
{
222+
const ASN1_OBJECT *algorithm {};
223+
X509_ALGOR_get0(&algorithm, nullptr, nullptr, OCSP_resp_get0_tbs_sigalg(basic.get()));
224+
int digest = NID_undef;
225+
X509 *signer {};
226+
if(OBJ_find_sigid_algs(OBJ_obj2nid(algorithm), &digest, nullptr) == 1 && digest == NID_sha1 &&
227+
OCSP_resp_get0_signer(basic.get(), &signer, stack.get()) == 1 && signer)
228+
{
229+
// OCSP_basic_verify uses the responder certificate's context. External
230+
// certificates take precedence over certificates embedded in the response.
231+
auto local = X509CertStore::legacyCertificate(signer);
232+
if(local && sk_X509_insert(stack.get(), local.get(), 0) != 0)
233+
{
234+
verified = OCSP_basic_verify(basic.get(), stack.get(), store.get(), OCSP_NOCHECKS | OCSP_PARTIAL_CHAIN);
235+
sk_X509_delete(stack.get(), 0);
236+
}
237+
}
238+
}
239+
if(verified != 1)
220240
{
221241
unsigned long err = ERR_get_error();
222242
if(ERR_GET_LIB(err) == ERR_LIB_OCSP &&

‎src/crypto/X509CertStore.cpp‎

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
#include <openssl/ssl.h>
3333
#include <openssl/x509v3.h>
3434

35+
#ifndef _WIN32
36+
#include <dlfcn.h>
37+
#endif
38+
3539
using namespace digidoc;
3640
using namespace std;
3741

@@ -166,6 +170,38 @@ unique_free_t<X509_STORE> X509CertStore::createStore(const Type &type, tm &tm)
166170
return store;
167171
}
168172

173+
unique_free_t<X509> X509CertStore::legacyCertificate(X509 *cert)
174+
{
175+
#ifndef _WIN32
176+
// Fedora/RHEL can disable SHA-1 even for historical certificate and OCSP signatures.
177+
// Keep that exception in a private context, leaving the caller's policy intact.
178+
static const auto context = [] {
179+
auto ctx = make_unique_ptr<OSSL_LIB_CTX_free>(nullptr);
180+
auto *allow = reinterpret_cast<int(*)(void*, int, int)>(
181+
dlsym(RTLD_DEFAULT, "ossl_ctx_legacy_digest_signatures_allowed_set"));
182+
if(!allow)
183+
return ctx;
184+
ctx.reset(OSSL_LIB_CTX_new());
185+
if(!ctx || OSSL_LIB_CTX_load_config(ctx.get(), nullptr) != 1 || allow(ctx.get(), 1, 0) != 1)
186+
{
187+
WARN("Failed to enable legacy certificate verification in private OpenSSL context");
188+
ctx.reset();
189+
}
190+
return ctx;
191+
}();
192+
if(context)
193+
{
194+
ERR_clear_error();
195+
auto der = i2d<i2d_X509>(cert);
196+
X509 *local = X509_new_ex(context.get(), nullptr);
197+
// d2i_X509 frees local and sets it to nullptr on failure.
198+
if(const unsigned char *data = der.data(); local && d2i_X509(&local, &data, long(der.size())))
199+
return {local, X509_free};
200+
}
201+
#endif
202+
return {nullptr, X509_free};
203+
}
204+
169205
int X509CertStore::validate(int ok, X509_STORE_CTX *ctx)
170206
{
171207
switch(X509_STORE_CTX_get_error(ctx))
@@ -201,9 +237,21 @@ int X509CertStore::validate(int ok, X509_STORE_CTX *ctx)
201237
if(none_of(s.certs, [&](const X509Cert &issuer) {
202238
if(issuer == x509) // certificate is listed by service
203239
return true;
204-
if(X509_check_issued(issuer.handle(), x509) == X509_V_OK && // certificate is issued by service (function checks only issuer name)
205-
X509_verify(x509, X509_get0_pubkey(issuer.handle())) == 1) // certificate is signed by service
206-
return true;
240+
if(X509_check_issued(issuer.handle(), x509) == X509_V_OK) // certificate is issued by service (function checks only issuer name)
241+
{
242+
auto *key = X509_get0_pubkey(issuer.handle());
243+
if(X509_verify(x509, key) == 1) // certificate is signed by service
244+
return true;
245+
#ifndef _WIN32
246+
if(int digest = NID_undef;
247+
OBJ_find_sigid_algs(X509_get_signature_nid(x509), &digest, nullptr) == 1 && digest == NID_sha1)
248+
{
249+
// X509_verify uses the context of the certificate, not X509_STORE_CTX.
250+
if(auto local = legacyCertificate(x509); local && X509_verify(local.get(), key) == 1)
251+
return true;
252+
}
253+
#endif
254+
}
207255
ERR_clear_error();
208256
return false;
209257
})) // certificate is trusted by service

‎src/crypto/X509CertStore.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
using X509_STORE = struct x509_store_st;
3232
using X509_STORE_CTX = struct x509_store_ctx_st;
33+
using X509 = struct x509_st;
3334

3435
namespace digidoc
3536
{
@@ -50,6 +51,7 @@ namespace digidoc
5051
X509Cert findIssuer(const X509Cert &cert, const Type &type) const;
5152
static X509Cert issuerFromAIA(const X509Cert &cert);
5253
static unique_free_t<X509_STORE> createStore(const Type &type, tm &tm);
54+
static unique_free_t<X509> legacyCertificate(X509 *cert);
5355
void update() const;
5456
bool verify(const X509Cert &cert, bool noqscd, tm validation_time, const std::vector<X509Cert> &untrusted) const;
5557

‎src/util/log.h‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,22 @@ namespace digidoc
5454
#define EXCEPTION_ADD(_main, ...) _main.addCause(digidoc::Exception(EXCEPTION_PARAMS(__VA_ARGS__)))
5555
#define THROW(...) throw digidoc::Exception(EXCEPTION_PARAMS(__VA_ARGS__))
5656
#define THROW_CAUSE(_cause, ...) throw digidoc::Exception(EXCEPTION_PARAMS(__VA_ARGS__), _cause)
57+
58+
#ifdef WIN32
59+
#define DIGIDOCPP_WARNING_PUSH __pragma(warning(push))
60+
#define DIGIDOCPP_WARNING_POP __pragma(warning(pop))
61+
#define DIGIDOCPP_WARNING_DISABLE_CLANG(text)
62+
#define DIGIDOCPP_WARNING_DISABLE_GCC(text)
63+
#define DIGIDOCPP_WARNING_DISABLE_MSVC(number) __pragma(warning(disable: number))
64+
#else
65+
#define DIGIDOCPP_DO_PRAGMA(text) _Pragma(#text)
66+
#define DIGIDOCPP_WARNING_PUSH DIGIDOCPP_DO_PRAGMA(GCC diagnostic push)
67+
#define DIGIDOCPP_WARNING_POP DIGIDOCPP_DO_PRAGMA(GCC diagnostic pop)
68+
#if __clang__
69+
#define DIGIDOCPP_WARNING_DISABLE_CLANG(text) DIGIDOCPP_DO_PRAGMA(clang diagnostic ignored text)
70+
#else
71+
#define DIGIDOCPP_WARNING_DISABLE_CLANG(text)
72+
#endif
73+
#define DIGIDOCPP_WARNING_DISABLE_GCC(text) DIGIDOCPP_DO_PRAGMA(GCC diagnostic ignored text)
74+
#define DIGIDOCPP_WARNING_DISABLE_MSVC(text)
75+
#endif

‎test/CMakeLists.txt‎

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
set_env(TEST_FORMAT XML CACHE STRING "Test result format (XML/JUNIT)")
21
set( CMAKE_SKIP_RPATH OFF )
32
add_definitions(
43
-DDIGIDOCPPCONF="${PROJECT_SOURCE_DIR}/etc/schema"
@@ -10,11 +9,10 @@ add_executable(TSLTests TSLTests.cpp)
109
target_link_libraries(unittests digidocpp digidocpp_tsl Boost::unit_test_framework)
1110
target_link_libraries(TSLTests digidocpp digidocpp_util Boost::unit_test_framework)
1211
if(WIN32)
13-
string(REPLACE "/EHsc" "/EHa" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
1412
set_target_properties(unittests TSLTests PROPERTIES COMPILE_FLAGS "/bigobj")
1513
endif()
16-
add_test(NAME runtest
17-
COMMAND unittests --build_info=YES --report_level=no --logger=${TEST_FORMAT},all,$<TARGET_FILE_DIR:unittests>/libdigidocpp.xml -- ${CMAKE_CURRENT_SOURCE_DIR}/data
14+
add_test(NAME unittests
15+
COMMAND unittests --build_info=YES --report_level=no -- ${CMAKE_CURRENT_SOURCE_DIR}/data
1816
WORKING_DIRECTORY $<TARGET_FILE_DIR:digidocpp>
1917
)
2018

@@ -42,5 +40,3 @@ foreach(TEST CA-withdrawn-granted-before CA-noqscd-granted-before
4240
WORKING_DIRECTORY $<TARGET_FILE_DIR:digidocpp>
4341
)
4442
endforeach()
45-
46-
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} -C $<CONFIG> DEPENDS unittests TSLTests)

0 commit comments

Comments
 (0)