From 2a8ef024301469e4f3c0957f060fd126c36c66b5 Mon Sep 17 00:00:00 2001 From: Marcin Pogorzelski Date: Wed, 28 Aug 2024 09:25:38 +0200 Subject: [PATCH 1/4] Add possiblity to load providers and use them in Poco --- NetSSL_OpenSSL/include/Poco/Net/Context.h | 47 ++++++++++++++++- NetSSL_OpenSSL/src/Context.cpp | 61 ++++++++++++++++++----- 2 files changed, 94 insertions(+), 14 deletions(-) diff --git a/NetSSL_OpenSSL/include/Poco/Net/Context.h b/NetSSL_OpenSSL/include/Poco/Net/Context.h index c707e343df..fe231d2b3c 100644 --- a/NetSSL_OpenSSL/include/Poco/Net/Context.h +++ b/NetSSL_OpenSSL/include/Poco/Net/Context.h @@ -28,6 +28,7 @@ #include "Poco/SharedPtr.h" #include "Poco/AutoPtr.h" #include +#include #include @@ -155,6 +156,9 @@ class NetSSL_API Context: public Poco::RefCountedObject Params(KeyDHGroup dhBits = KEY_DH_GROUP_2048); /// Initializes the struct with default values. + std::string providerName; + OSSL_LIB_CTX *libctx = nullptr; + std::string privateKeyFile; /// Path to the private key file used for encryption. /// Can be empty if no private key file is used. @@ -304,6 +308,44 @@ class NetSSL_API Context: public Poco::RefCountedObject /// Note that a private key and/or certificate must be specified with /// usePrivateKey()/useCertificate() before the Context can be used. + Context( Usage usage, + OSSL_LIB_CTX *libctx, + const std::string &provider, + VerificationMode verificationMode = VERIFY_RELAXED, + int verificationDepth = 9, + bool loadDefaultCAs = false, + const std::string &cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH" ); + /// Creates a Context. + /// + /// * usage specifies whether the context is used by a client or server. + /// * libctx pointer to OpenSSL library context (i.e. from OSSL_LIB_CTX_new) + /// * provider specifies the custom provider query string + /// * verificationMode specifies whether and how peer certificates are validated. + /// * verificationDepth sets the upper limit for verification chain sizes. Verification + /// will fail if a certificate chain larger than this is encountered. + /// * loadDefaultCAs specifies whether the builtin CA certificates from OpenSSL are used. + /// * cipherList specifies the supported ciphers in OpenSSL notation. + /// + /// Note that a private key and/or certificate must be specified with + /// usePrivateKey()/useCertificate() or loaded through a registered provider before the Context can be used. + /// + /// Example usage: + /// * // Create a OpenSSL libary context and set default provider library search path. + /// * auto ctx = OSSL_LIB_CTX_new(); + /// * OSSL_PROVIDER_set_default_search_path( ctx, "" ); + /// * + /// * // Load providers + /// * auto provider = OSSL_PROVIDER_load( ctx, "" ); + /// * auto providerDefault = OSSL_PROVIDER_load( ctx, "default" ); + /// * + /// * // Create context to be used by server. + /// * auto serverCtx = new Poco::Net::Context( Poco::Net::Context::SERVER_USE, ctx, "", Poco::Net::Context::VERIFY_STRICT ); + /// * ... + /// * // clean-up + /// * OSSL_PROVIDER_unload( provider ); + /// * OSSL_PROVIDER_unload( providerDefault ); + /// * OSSL_LIB_CTX_free( ctx ); + ~Context(); /// Destroys the Context. @@ -523,6 +565,9 @@ class NetSSL_API Context: public Poco::RefCountedObject void init(const Params& params); /// Initializes the Context with the given parameters. + void initContext(const Params& params, const SSL_METHOD *method); + /// Helper for init. + void initDH(KeyDHGroup keyDHGroup, const std::string& dhFile); /// Initializes the Context with Diffie-Hellman parameters. @@ -530,7 +575,7 @@ class NetSSL_API Context: public Poco::RefCountedObject /// Initializes the Context with Elliptic-Curve Diffie-Hellman key /// exchange curve parameters. - void createSSLContext(); + void createSSLContext( const Params ¶ms ); /// Create a SSL_CTX object according to Context configuration. Usage _usage; diff --git a/NetSSL_OpenSSL/src/Context.cpp b/NetSSL_OpenSSL/src/Context.cpp index 51933c1e0b..a21ffa2726 100644 --- a/NetSSL_OpenSSL/src/Context.cpp +++ b/NetSSL_OpenSSL/src/Context.cpp @@ -47,7 +47,8 @@ Context::Params::Params(KeyDHGroup dhBits): ocspStaplingVerification(false), cipherList("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"), dhGroup(dhBits), - securityLevel(SECURITY_LEVEL_NONE) + securityLevel(SECURITY_LEVEL_NONE), + libctx(0) { } @@ -113,6 +114,32 @@ Context::Context( } +Context::Context( + Usage usage, + OSSL_LIB_CTX *libctx, + const std::string &provider, + VerificationMode verificationMode, + int verificationDepth, + bool loadDefaultCAs, + const std::string &cipherList ) : + _usage( usage ), + _mode( verificationMode ), + _pSSLContext( 0 ), + _extendedCertificateVerification( true ), + _ocspStaplingResponseVerification( false ) +{ + Params params; + params.providerName = provider; + params.libctx = libctx; + params.verificationMode = verificationMode; + params.verificationDepth = verificationDepth; + params.loadDefaultCAs = loadDefaultCAs; + params.cipherList = cipherList; + + init( params ); +} + + Context::~Context() { try @@ -131,7 +158,7 @@ void Context::init(const Params& params) { Poco::Crypto::OpenSSLInitializer::initialize(); - createSSLContext(); + createSSLContext( params ); try { @@ -562,8 +589,16 @@ void Context::setInvalidCertificateHandler(InvalidCertificateHandlerPtr pInvalid _pInvalidCertificateHandler = pInvalidCertificateHandler; } +void Context::initContext(const Params& params, const SSL_METHOD *method) { + if ( nullptr != params.libctx && !params.providerName.empty() ) { + _pSSLContext = SSL_CTX_new_ex( params.libctx, params.providerName.c_str(), method ); + } + else { + _pSSLContext = SSL_CTX_new( method ); + } +} -void Context::createSSLContext() +void Context::createSSLContext( const Params ¶ms ) { int minTLSVersion = 0; @@ -571,54 +606,54 @@ void Context::createSSLContext() { case CLIENT_USE: case TLS_CLIENT_USE: - _pSSLContext = SSL_CTX_new(TLS_client_method()); + initContext(params, TLS_client_method()); minTLSVersion = TLS1_VERSION; break; case SERVER_USE: case TLS_SERVER_USE: - _pSSLContext = SSL_CTX_new(TLS_server_method()); + initContext(params, TLS_server_method()); minTLSVersion = TLS1_VERSION; break; case TLSV1_CLIENT_USE: - _pSSLContext = SSL_CTX_new(TLS_client_method()); + initContext(params, TLS_client_method()); minTLSVersion = TLS1_VERSION; break; case TLSV1_SERVER_USE: - _pSSLContext = SSL_CTX_new(TLS_server_method()); + initContext(params, TLS_server_method()); minTLSVersion = TLS1_VERSION; break; #if !defined(OPENSSL_NO_TLS1) case TLSV1_1_CLIENT_USE: - _pSSLContext = SSL_CTX_new(TLS_client_method()); + initContext(params, TLS_client_method()); minTLSVersion = TLS1_1_VERSION; break; case TLSV1_1_SERVER_USE: - _pSSLContext = SSL_CTX_new(TLS_server_method()); + initContext(params, TLS_server_method()); minTLSVersion = TLS1_1_VERSION; break; case TLSV1_2_CLIENT_USE: - _pSSLContext = SSL_CTX_new(TLS_client_method()); + initContext(params, TLS_client_method()); minTLSVersion = TLS1_2_VERSION; break; case TLSV1_2_SERVER_USE: - _pSSLContext = SSL_CTX_new(TLS_server_method()); + initContext(params, TLS_server_method()); minTLSVersion = TLS1_2_VERSION; break; case TLSV1_3_CLIENT_USE: - _pSSLContext = SSL_CTX_new(TLS_client_method()); + initContext(params, TLS_client_method()); minTLSVersion = TLS1_3_VERSION; break; case TLSV1_3_SERVER_USE: - _pSSLContext = SSL_CTX_new(TLS_server_method()); + initContext(params, TLS_server_method()); minTLSVersion = TLS1_3_VERSION; break; #endif From 6ac817570f1a61ddf4e28e63252dd5067c3c1e17 Mon Sep 17 00:00:00 2001 From: Marcin Pogorzelski Date: Mon, 2 Sep 2024 09:18:17 +0200 Subject: [PATCH 2/4] Add OpenSSL 3.x version check for provider API --- NetSSL_OpenSSL/include/Poco/Net/Context.h | 8 ++++++++ NetSSL_OpenSSL/src/Context.cpp | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/NetSSL_OpenSSL/include/Poco/Net/Context.h b/NetSSL_OpenSSL/include/Poco/Net/Context.h index fe231d2b3c..d723b46f90 100644 --- a/NetSSL_OpenSSL/include/Poco/Net/Context.h +++ b/NetSSL_OpenSSL/include/Poco/Net/Context.h @@ -28,7 +28,11 @@ #include "Poco/SharedPtr.h" #include "Poco/AutoPtr.h" #include + +#if POCO_OPENSSL_VERSION_PREREQ(3, 0, 0) #include +#endif + #include @@ -156,8 +160,10 @@ class NetSSL_API Context: public Poco::RefCountedObject Params(KeyDHGroup dhBits = KEY_DH_GROUP_2048); /// Initializes the struct with default values. +#if POCO_OPENSSL_VERSION_PREREQ(3, 0, 0) std::string providerName; OSSL_LIB_CTX *libctx = nullptr; +#endif std::string privateKeyFile; /// Path to the private key file used for encryption. @@ -308,6 +314,7 @@ class NetSSL_API Context: public Poco::RefCountedObject /// Note that a private key and/or certificate must be specified with /// usePrivateKey()/useCertificate() before the Context can be used. +#if POCO_OPENSSL_VERSION_PREREQ(3, 0, 0) Context( Usage usage, OSSL_LIB_CTX *libctx, const std::string &provider, @@ -345,6 +352,7 @@ class NetSSL_API Context: public Poco::RefCountedObject /// * OSSL_PROVIDER_unload( provider ); /// * OSSL_PROVIDER_unload( providerDefault ); /// * OSSL_LIB_CTX_free( ctx ); +#endif ~Context(); /// Destroys the Context. diff --git a/NetSSL_OpenSSL/src/Context.cpp b/NetSSL_OpenSSL/src/Context.cpp index a21ffa2726..60afa76558 100644 --- a/NetSSL_OpenSSL/src/Context.cpp +++ b/NetSSL_OpenSSL/src/Context.cpp @@ -47,8 +47,10 @@ Context::Params::Params(KeyDHGroup dhBits): ocspStaplingVerification(false), cipherList("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"), dhGroup(dhBits), - securityLevel(SECURITY_LEVEL_NONE), - libctx(0) + securityLevel(SECURITY_LEVEL_NONE) +#if POCO_OPENSSL_VERSION_PREREQ(3, 0, 0) + ,libctx(0) +#endif { } @@ -114,6 +116,8 @@ Context::Context( } +#if POCO_OPENSSL_VERSION_PREREQ(3, 0, 0) + Context::Context( Usage usage, OSSL_LIB_CTX *libctx, @@ -139,6 +143,8 @@ Context::Context( init( params ); } +#endif + Context::~Context() { @@ -590,12 +596,16 @@ void Context::setInvalidCertificateHandler(InvalidCertificateHandlerPtr pInvalid } void Context::initContext(const Params& params, const SSL_METHOD *method) { +#if POCO_OPENSSL_VERSION_PREREQ(3, 0, 0) if ( nullptr != params.libctx && !params.providerName.empty() ) { _pSSLContext = SSL_CTX_new_ex( params.libctx, params.providerName.c_str(), method ); } else { _pSSLContext = SSL_CTX_new( method ); } +#else + _pSSLContext = SSL_CTX_new( method ); +#endif } void Context::createSSLContext( const Params ¶ms ) From 12d357c3088bd197f2e3368fc6920353d9ab370c Mon Sep 17 00:00:00 2001 From: Marcin Pogorzelski Date: Tue, 29 Sep 2026 20:59:31 +0200 Subject: [PATCH 3/4] Fixed issue with empty providerName drops the libctx --- NetSSL_OpenSSL/src/Context.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NetSSL_OpenSSL/src/Context.cpp b/NetSSL_OpenSSL/src/Context.cpp index 60afa76558..0e36914d74 100644 --- a/NetSSL_OpenSSL/src/Context.cpp +++ b/NetSSL_OpenSSL/src/Context.cpp @@ -597,8 +597,8 @@ void Context::setInvalidCertificateHandler(InvalidCertificateHandlerPtr pInvalid void Context::initContext(const Params& params, const SSL_METHOD *method) { #if POCO_OPENSSL_VERSION_PREREQ(3, 0, 0) - if ( nullptr != params.libctx && !params.providerName.empty() ) { - _pSSLContext = SSL_CTX_new_ex( params.libctx, params.providerName.c_str(), method ); + if ( nullptr != params.libctx ) { + _pSSLContext = SSL_CTX_new_ex( params.libctx, params.providerName.empty() ? nullptr : params.providerName.c_str(), method ); } else { _pSSLContext = SSL_CTX_new( method ); From 3189209e3f9482ef3d67c8d99d4eea08930bc9f4 Mon Sep 17 00:00:00 2001 From: Marcin Pogorzelski Date: Wed, 30 Sep 2026 06:36:17 +0200 Subject: [PATCH 4/4] Add test cases for context covering openssl propq --- NetSSL_OpenSSL/testsuite/src/ContextTest.cpp | 78 ++++++++++++++++++++ NetSSL_OpenSSL/testsuite/src/ContextTest.h | 4 + 2 files changed, 82 insertions(+) diff --git a/NetSSL_OpenSSL/testsuite/src/ContextTest.cpp b/NetSSL_OpenSSL/testsuite/src/ContextTest.cpp index 7b232a9df2..e243866a9c 100644 --- a/NetSSL_OpenSSL/testsuite/src/ContextTest.cpp +++ b/NetSSL_OpenSSL/testsuite/src/ContextTest.cpp @@ -33,6 +33,7 @@ using Poco::Crypto::X509Certificate; using Poco::Net::Context; using Poco::Net::SSLContextException; +using Poco::Net::SSLException; using Poco::Net::SSLManager; using Poco::Util::Application; @@ -127,6 +128,80 @@ void ContextTest::testBuiltInDHParameters() assertEqual (std::string("dh_2048_256"), negotiatedDHGroup(Context::KEY_DH_GROUP_2048)); assertEqual (std::string("dh_1024_160"), negotiatedDHGroup(Context::KEY_DH_GROUP_1024)); } + + +void ContextTest::testProviderContext() +{ + using LibCtxPtr = std::unique_ptr; + LibCtxPtr pLibCtx(OSSL_LIB_CTX_new(), &OSSL_LIB_CTX_free); + assertNotNullPtr (pLibCtx.get()); + + OSSL_PROVIDER* pProvider = OSSL_PROVIDER_load(pLibCtx.get(), "default"); + assertNotNullPtr (pProvider); + + Context::Ptr pContext = new Context( + Context::TLS_SERVER_USE, + pLibCtx.get(), + "provider=default", + Context::VERIFY_NONE); + assertNotNullPtr (pContext->sslContext()); + + OSSL_PROVIDER_unload(pProvider); +} + + +void ContextTest::testProviderContextLibctxOnlyIsUsed() +{ + + using LibCtxPtr = std::unique_ptr; + LibCtxPtr pLibCtx(OSSL_LIB_CTX_new(), &OSSL_LIB_CTX_free); + assertNotNullPtr (pLibCtx.get()); + + OSSL_PROVIDER* pProvider = OSSL_PROVIDER_load(pLibCtx.get(), "default"); + assertNotNullPtr (pProvider); + + Context::Ptr pContext = new Context( + Context::TLS_SERVER_USE, + pLibCtx.get(), + "", // no provider query string, only a custom libctx + Context::VERIFY_NONE); + assertNotNullPtr (pContext->sslContext()); + + OSSL_PROVIDER_unload(pProvider); +} + + +void ContextTest::testProviderContextInvalidProviderQueryRejected() +{ + ErrorQueueCleaner cleaner; + + using LibCtxPtr = std::unique_ptr; + LibCtxPtr pLibCtx(OSSL_LIB_CTX_new(), &OSSL_LIB_CTX_free); + assertNotNullPtr (pLibCtx.get()); + + using ProviderPtr = std::unique_ptr; + ProviderPtr pProvider(OSSL_PROVIDER_load(pLibCtx.get(), "default"), &OSSL_PROVIDER_unload); + assertNotNullPtr (pProvider.get()); + + Context::Params params; + params.libctx = pLibCtx.get(); + params.providerName = "provider=nonexistent-provider"; + params.cipherSuites = "TLS_AES_256_GCM_SHA384"; + params.verificationMode = Context::VERIFY_NONE; + + ERR_clear_error(); + try + { + Context::Ptr pContext = new Context(Context::TLS_SERVER_USE, params); + fail("unresolvable provider query string - must throw"); + } + catch (SSLContextException&) + { + } + catch ( SSLException & ) + { + } +} #endif @@ -276,6 +351,9 @@ CppUnit::Test* ContextTest::suite() CppUnit_addTest(pSuite, ContextTest, testDHParametersRejectedBySecurityLevel); #if POCO_OPENSSL_VERSION_PREREQ(3, 0, 0) CppUnit_addTest(pSuite, ContextTest, testBuiltInDHParameters); + CppUnit_addTest(pSuite, ContextTest, testProviderContext); + CppUnit_addTest(pSuite, ContextTest, testProviderContextLibctxOnlyIsUsed); + CppUnit_addTest(pSuite, ContextTest, testProviderContextInvalidProviderQueryRejected); #endif CppUnit_addTest(pSuite, ContextTest, testAddChainCertificateWithoutX509); CppUnit_addTest(pSuite, ContextTest, testClientContextIgnoresDHParameters); diff --git a/NetSSL_OpenSSL/testsuite/src/ContextTest.h b/NetSSL_OpenSSL/testsuite/src/ContextTest.h index cd79dda4d5..237f8d3de5 100644 --- a/NetSSL_OpenSSL/testsuite/src/ContextTest.h +++ b/NetSSL_OpenSSL/testsuite/src/ContextTest.h @@ -33,6 +33,9 @@ class ContextTest: public CppUnit::TestCase void testDHParametersRejectedBySecurityLevel(); #if POCO_OPENSSL_VERSION_PREREQ(3, 0, 0) void testBuiltInDHParameters(); + void testProviderContext(); + void testProviderContextLibctxOnlyIsUsed(); + void testProviderContextInvalidProviderQueryRejected(); #endif void testAddChainCertificateWithoutX509(); void testClientContextIgnoresDHParameters(); @@ -50,6 +53,7 @@ class ContextTest: public CppUnit::TestCase /// Returns the OpenSSL name of the DH group that a server Context with /// the given built-in parameters sends in a TLS 1.2 DHE handshake. #endif + };