QSslSocket::transmit (macOS/iOS) - do not use invalid context

1. QSslSocketBackendPrivate::transmit can invalidate SSL context
  causing subsequent SSLWrite or SSLRead calls to fail; these report
  errSecParam (as null context is an invalid parameter) spuriously,
  when we should rather report the cause of invalidation.  The OpenSSL
  backend can trigger this when it aborts connection during an SSL
  handshake, on an sslErrors signal.  As transmit() emits readReady(),
  a directly connected slot can trigger the same problem if it aborts or
  closes.

2. If during peer verification (and in checkSslErrors) we disconnect
on sslErrors signal, peer verification must be considered failed and
should not continue handshake/set connectionEncrypted.

Task-number: QTBUG-52975
Task-number: QTBUG-53906
Change-Id: Iacd3b489a4156e25ef3460ace40d21f34a946bed
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Timur Pocheptsov 2016-06-15 10:01:14 +02:00
parent 7a8330ddf7
commit faeaddc1b9

View File

@ -634,7 +634,7 @@ void QSslSocketBackendPrivate::transmit()
if (connectionEncrypted && !writeBuffer.isEmpty()) {
qint64 totalBytesWritten = 0;
while (writeBuffer.nextDataBlockSize() > 0) {
while (writeBuffer.nextDataBlockSize() > 0 && context) {
const size_t nextDataBlockSize = writeBuffer.nextDataBlockSize();
size_t writtenBytes = 0;
const OSStatus err = SSLWrite(context, writeBuffer.readPointer(), nextDataBlockSize, &writtenBytes);
@ -668,7 +668,7 @@ void QSslSocketBackendPrivate::transmit()
if (connectionEncrypted) {
QVarLengthArray<char, 4096> data;
while (true) {
while (context) {
size_t readBytes = 0;
data.resize(4096);
const OSStatus err = SSLRead(context, data.data(), data.size(), &readBytes);
@ -1305,7 +1305,10 @@ bool QSslSocketBackendPrivate::verifyPeerTrust()
// report errors
if (!errors.isEmpty() && !canIgnoreVerify) {
sslErrors = errors;
if (!checkSslErrors())
// checkSslErrors unconditionally emits sslErrors:
// a user's slot can abort/close/disconnect on this
// signal, so we also test the socket's state:
if (!checkSslErrors() || q->state() != QAbstractSocket::ConnectedState)
return false;
} else {
sslErrors.clear();