fix(Socket): shutdown fixes from pull #3448

This commit is contained in:
Alex Fabijanic
2022-03-31 19:03:27 +00:00
parent 3bab3548f4
commit 3fb001f397
6 changed files with 85 additions and 1 deletions

View File

@@ -126,6 +126,16 @@ public:
PROTO_TLSV1_3 = 0x20 PROTO_TLSV1_3 = 0x20
}; };
enum SecurityLevel
{
SECURITY_LEVEL_NONE = 0,
SECURITY_LEVEL_80_BITS = 1,
SECURITY_LEVEL_112_BITS = 2,
SECURITY_LEVEL_128_BITS = 3,
SECURITY_LEVEL_192_BITS = 4,
SECURITY_LEVEL_256_BITS = 5
};
struct NetSSL_API Params struct NetSSL_API Params
{ {
Params(); Params();
@@ -193,6 +203,11 @@ public:
/// and other TLSv1.3 ephemeral key negotiation, based /// and other TLSv1.3 ephemeral key negotiation, based
/// on the group names defined by OpenSSL. Defaults to /// on the group names defined by OpenSSL. Defaults to
/// "X448:X25519:ffdhe4096:ffdhe3072:ffdhe2048:ffdhe6144:ffdhe8192:P-521:P-384:P-256" /// "X448:X25519:ffdhe4096:ffdhe3072:ffdhe2048:ffdhe6144:ffdhe8192:P-521:P-384:P-256"
SecurityLevel securityLevel;
/// Defines minimal number of security bits allowed.
/// Requires OpenSSL >= 1.1 to be effective.
}; };
using InvalidCertificateHandlerPtr = Poco::SharedPtr<InvalidCertificateHandler>; using InvalidCertificateHandlerPtr = Poco::SharedPtr<InvalidCertificateHandler>;
@@ -420,6 +435,9 @@ public:
/// Returns the InvalidCertificateHandler set for this Context, /// Returns the InvalidCertificateHandler set for this Context,
/// or a null pointer if none has been set. /// or a null pointer if none has been set.
void setSecurityLevel(SecurityLevel level);
/// Sets the security level.
private: private:
void init(const Params& params); void init(const Params& params);
/// Initializes the Context with the given parameters. /// Initializes the Context with the given parameters.

View File

@@ -64,6 +64,9 @@ public:
bool isSecure() const; bool isSecure() const;
/// Returns true if the session is FTPS. /// Returns true if the session is FTPS.
void forceSessionReuse(bool force = true);
/// Enable or disable session reusing
protected: protected:
virtual StreamSocket establishDataConnection(const std::string& command, const std::string& arg); virtual StreamSocket establishDataConnection(const std::string& command, const std::string& arg);
/// Create secure data connection /// Create secure data connection
@@ -80,6 +83,7 @@ private:
bool _enableFTPS = true; bool _enableFTPS = true;
bool _secureDataConnection = false; bool _secureDataConnection = false;
bool _forceSessionReuse = false;
Context::Ptr _pContext; Context::Ptr _pContext;
}; };
@@ -95,6 +99,12 @@ inline bool FTPSClientSession::isSecure() const
} }
inline void FTPSClientSession::forceSessionReuse(bool force)
{
_forceSessionReuse = force;
}
} } // namespace Poco::Net } } // namespace Poco::Net

View File

@@ -281,6 +281,7 @@ private:
bool _needHandshake; bool _needHandshake;
std::string _peerHostName; std::string _peerHostName;
Session::Ptr _pSession; Session::Ptr _pSession;
bool _bidirectShutdown = true;
friend class SecureStreamSocketImpl; friend class SecureStreamSocketImpl;
}; };

View File

@@ -36,7 +36,8 @@ Context::Params::Params():
loadDefaultCAs(false), loadDefaultCAs(false),
ocspStaplingVerification(false), ocspStaplingVerification(false),
cipherList("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"), cipherList("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"),
dhUse2048Bits(false) dhUse2048Bits(false),
securityLevel(SECURITY_LEVEL_NONE)
{ {
} }
@@ -125,6 +126,9 @@ void Context::init(const Params& params)
try try
{ {
int errCode = 0; int errCode = 0;
setSecurityLevel(params.securityLevel);
if (!params.caLocation.empty()) if (!params.caLocation.empty())
{ {
Poco::File aFile(params.caLocation); Poco::File aFile(params.caLocation);
@@ -204,6 +208,14 @@ void Context::init(const Params& params)
} }
void Context::setSecurityLevel(SecurityLevel level)
{
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
SSL_CTX_set_security_level(_pSSLContext, static_cast<int>(level));
#endif
}
void Context::useCertificate(const Poco::Crypto::X509Certificate& certificate) void Context::useCertificate(const Poco::Crypto::X509Certificate& certificate)
{ {
int errCode = SSL_CTX_use_certificate(_pSSLContext, const_cast<X509*>(certificate.certificate())); int errCode = SSL_CTX_use_certificate(_pSSLContext, const_cast<X509*>(certificate.certificate()));

View File

@@ -127,6 +127,14 @@ StreamSocket FTPSClientSession::establishDataConnection(const std::string& comma
{ {
Poco::Net::SecureStreamSocket sss(Poco::Net::SecureStreamSocket::attach(ss, pSecure->context(), pSecure->currentSession())); Poco::Net::SecureStreamSocket sss(Poco::Net::SecureStreamSocket::attach(ss, pSecure->context(), pSecure->currentSession()));
ss = sss; ss = sss;
if (_forceSessionReuse)
{
sss.setLazyHandshake(false);
if (sss.completeHandshake() != 1)
throw Poco::Net::FTPException("SSL Session HANDSHAKE error");
if (!sss.sessionWasReused())
throw Poco::Net::FTPException("SSL Session for data connection was not reused");
}
} }
} }
return ss; return ss;

View File

@@ -255,7 +255,41 @@ void SecureSocketImpl::shutdown()
// most web browsers, so we just set the shutdown // most web browsers, so we just set the shutdown
// flag by calling SSL_shutdown() once and be // flag by calling SSL_shutdown() once and be
// done with it. // done with it.
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
int rc = 0;
if (!_bidirectShutdown)
rc = SSL_shutdown(_pSSL);
else
{
Poco::Timespan recvTimeout = _pSocket->getReceiveTimeout();
Poco::Timespan pollTimeout(0, 100000);
Poco::Timestamp tsNow;
do
{
rc = SSL_shutdown(_pSSL);
if (rc == 1) break;
if (rc < 0)
{
int err = SSL_get_error(_pSSL, rc);
if (err == SSL_ERROR_WANT_READ)
_pSocket->poll(pollTimeout, Poco::Net::Socket::SELECT_READ);
else if (err == SSL_ERROR_WANT_WRITE)
_pSocket->poll(pollTimeout, Poco::Net::Socket::SELECT_WRITE);
else
{
int socketError = SocketImpl::lastError();
long lastError = ERR_get_error();
if ((err == SSL_ERROR_SSL) && (socketError == 0) && (lastError == 0x0A000123))
rc = 0;
break;
}
}
else _pSocket->poll(pollTimeout, Poco::Net::Socket::SELECT_READ);
} while (!tsNow.isElapsed(recvTimeout.totalMicroseconds()));
}
#else
int rc = SSL_shutdown(_pSSL); int rc = SSL_shutdown(_pSSL);
#endif
if (rc < 0) handleError(rc); if (rc < 0) handleError(rc);
if (_pSocket->getBlocking()) if (_pSocket->getBlocking())
{ {
@@ -328,6 +362,7 @@ int SecureSocketImpl::receiveBytes(void* buffer, int length, int flags)
rc = SSL_read(_pSSL, buffer, length); rc = SSL_read(_pSSL, buffer, length);
} }
while (mustRetry(rc)); while (mustRetry(rc));
_bidirectShutdown = false;
if (rc <= 0) if (rc <= 0)
{ {
return handleError(rc); return handleError(rc);