Page MenuHomePhorge

No OneTemporary

diff --git a/kdecore/network/ktcpsocket.cpp b/kdecore/network/ktcpsocket.cpp
index 29eb82698e..d746c8c9e6 100644
--- a/kdecore/network/ktcpsocket.cpp
+++ b/kdecore/network/ktcpsocket.cpp
@@ -1,1093 +1,1110 @@
/* This file is part of the KDE libraries
Copyright (C) 2007, 2008 Andreas Hartmetz <ahartmetz@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "ktcpsocket.h"
#include "ktcpsocket_p.h"
#include <kdebug.h>
#include <kurl.h>
#include <kglobal.h>
#include <ksslcertificatemanager.h>
#include <kstandarddirs.h>
#include <klocale.h>
#include <QtCore/QStringList>
#include <QtNetwork/QSslKey>
#include <QtNetwork/QSslCipher>
#include <QtNetwork/QHostAddress>
#include <QtNetwork/QNetworkProxy>
static KTcpSocket::SslVersion kSslVersionFromQ(QSsl::SslProtocol protocol)
{
switch (protocol) {
case QSsl::SslV2:
return KTcpSocket::SslV2;
case QSsl::SslV3:
return KTcpSocket::SslV3;
case QSsl::TlsV1:
return KTcpSocket::TlsV1;
case QSsl::AnyProtocol:
return KTcpSocket::AnySslVersion;
default:
return KTcpSocket::UnknownSslVersion;
}
}
static QSsl::SslProtocol qSslProtocolFromK(KTcpSocket::SslVersion sslVersion)
{
//### this lowlevel bit-banging is a little dangerous and a likely source of bugs
if (sslVersion == KTcpSocket::AnySslVersion) {
return QSsl::AnyProtocol;
}
//does it contain any valid protocol?
if (!(sslVersion & (KTcpSocket::SslV2 | KTcpSocket::SslV3 | KTcpSocket::TlsV1))) {
return QSsl::UnknownProtocol;
}
switch (sslVersion) {
case KTcpSocket::SslV2:
return QSsl::SslV2;
case KTcpSocket::SslV3:
return QSsl::SslV3;
case KTcpSocket::TlsV1:
return QSsl::TlsV1;
default:
//QSslSocket doesn't really take arbitrary combinations. It's one or all.
return QSsl::AnyProtocol;
}
}
//cipher class converter KSslCipher -> QSslCipher
class CipherCc
{
public:
CipherCc()
{
foreach (const QSslCipher &c, QSslSocket::supportedCiphers()) {
allCiphers.insert(c.name(), c);
}
}
QSslCipher converted(const KSslCipher &ksc)
{
return allCiphers.value(ksc.name());
}
private:
QHash<QString, QSslCipher> allCiphers;
};
class KSslErrorPrivate
{
public:
static KSslError::Error errorFromQSslError(QSslError::SslError e)
{
switch (e) {
case QSslError::NoError:
return KSslError::NoError;
case QSslError::UnableToGetLocalIssuerCertificate:
case QSslError::InvalidCaCertificate:
return KSslError::InvalidCertificateAuthorityCertificate;
case QSslError::InvalidNotBeforeField:
case QSslError::InvalidNotAfterField:
case QSslError::CertificateNotYetValid:
case QSslError::CertificateExpired:
return KSslError::ExpiredCertificate;
case QSslError::UnableToDecodeIssuerPublicKey:
case QSslError::SubjectIssuerMismatch:
case QSslError::AuthorityIssuerSerialNumberMismatch:
return KSslError::InvalidCertificate;
case QSslError::SelfSignedCertificate:
case QSslError::SelfSignedCertificateInChain:
return KSslError::SelfSignedCertificate;
case QSslError::CertificateRevoked:
return KSslError::RevokedCertificate;
case QSslError::InvalidPurpose:
return KSslError::InvalidCertificatePurpose;
case QSslError::CertificateUntrusted:
return KSslError::UntrustedCertificate;
case QSslError::CertificateRejected:
return KSslError::RejectedCertificate;
case QSslError::NoPeerCertificate:
return KSslError::NoPeerCertificate;
case QSslError::HostNameMismatch:
return KSslError::HostNameMismatch;
case QSslError::UnableToVerifyFirstCertificate:
case QSslError::UnableToDecryptCertificateSignature:
case QSslError::UnableToGetIssuerCertificate:
case QSslError::CertificateSignatureFailed:
return KSslError::CertificateSignatureFailed;
case QSslError::PathLengthExceeded:
return KSslError::PathLengthExceeded;
case QSslError::UnspecifiedError:
case QSslError::NoSslSupport:
default:
return KSslError::UnknownError;
}
}
static QString errorString(KSslError::Error e)
{
switch (e) {
case KSslError::NoError:
return i18nc("SSL error","No error");
case KSslError::InvalidCertificateAuthorityCertificate:
return i18nc("SSL error","The certificate authority's certificate is invalid");
case KSslError::ExpiredCertificate:
return i18nc("SSL error","The certificate has expired");
case KSslError::InvalidCertificate:
return i18nc("SSL error","The certificate is invalid");
case KSslError::SelfSignedCertificate:
return i18nc("SSL error","The certificate is not signed by any trusted certificate authority");
case KSslError::RevokedCertificate:
return i18nc("SSL error","The certificate has been revoked");
case KSslError::InvalidCertificatePurpose:
return i18nc("SSL error","The certificate is unsuitable for this purpose");
case KSslError::UntrustedCertificate:
return i18nc("SSL error","The root certificate authority's certificate is not trusted for this purpose");
case KSslError::RejectedCertificate:
return i18nc("SSL error","The certificate authority's certificate is marked to reject this certificate's purpose");
case KSslError::NoPeerCertificate:
return i18nc("SSL error","The peer did not present any certificate");
case KSslError::HostNameMismatch:
return i18nc("SSL error","The certificate does not apply to the given host");
case KSslError::CertificateSignatureFailed:
return i18nc("SSL error","The certificate cannot be verified for internal reasons");
case KSslError::PathLengthExceeded:
return i18nc("SSL error","The certificate chain is too long");
case KSslError::UnknownError:
default:
return i18nc("SSL error","Unknown error");
}
}
KSslError::Error error;
QSslCertificate certificate;
};
KSslError::KSslError(Error errorCode, const QSslCertificate &certificate)
: d(new KSslErrorPrivate())
{
d->error = errorCode;
d->certificate = certificate;
}
KSslError::KSslError(const QSslError &other)
: d(new KSslErrorPrivate())
{
d->error = KSslErrorPrivate::errorFromQSslError(other.error());
d->certificate = other.certificate();
}
KSslError::KSslError(const KSslError &other)
: d(new KSslErrorPrivate())
{
*d = *other.d;
}
KSslError::~KSslError()
{
delete d;
}
KSslError &KSslError::operator=(const KSslError &other)
{
*d = *other.d;
return *this;
}
KSslError::Error KSslError::error() const
{
return d->error;
}
QString KSslError::errorString() const
{
return KSslErrorPrivate::errorString(d->error);
}
QSslCertificate KSslError::certificate() const
{
return d->certificate;
}
class KTcpSocketPrivate
{
public:
KTcpSocketPrivate(KTcpSocket *qq)
: q(qq),
certificatesLoaded(false),
emittedReadyRead(false)
{
// create the instance, which sets Qt's static internal cert set to empty.
KSslCertificateManager::self();
}
KTcpSocket::State state(QAbstractSocket::SocketState s)
{
switch (s) {
case QAbstractSocket::UnconnectedState:
return KTcpSocket::UnconnectedState;
case QAbstractSocket::HostLookupState:
return KTcpSocket::HostLookupState;
case QAbstractSocket::ConnectingState:
return KTcpSocket::ConnectingState;
case QAbstractSocket::ConnectedState:
return KTcpSocket::ConnectedState;
case QAbstractSocket::ClosingState:
return KTcpSocket::ClosingState;
case QAbstractSocket::BoundState:
case QAbstractSocket::ListeningState:
//### these two are not relevant as long as this can't be a server socket
default:
return KTcpSocket::UnconnectedState; //the closest to "error"
}
}
KTcpSocket::EncryptionMode encryptionMode(QSslSocket::SslMode mode)
{
switch (mode) {
case QSslSocket::SslClientMode:
return KTcpSocket::SslClientMode;
case QSslSocket::SslServerMode:
return KTcpSocket::SslServerMode;
default:
return KTcpSocket::UnencryptedMode;
}
}
KTcpSocket::Error errorFromAbsSocket(QAbstractSocket::SocketError e)
{
switch (e) {
case QAbstractSocket::ConnectionRefusedError:
return KTcpSocket::ConnectionRefusedError;
case QAbstractSocket::RemoteHostClosedError:
return KTcpSocket::RemoteHostClosedError;
case QAbstractSocket::HostNotFoundError:
return KTcpSocket::HostNotFoundError;
case QAbstractSocket::SocketAccessError:
return KTcpSocket::SocketAccessError;
case QAbstractSocket::SocketResourceError:
return KTcpSocket::SocketResourceError;
case QAbstractSocket::SocketTimeoutError:
return KTcpSocket::SocketTimeoutError;
case QAbstractSocket::NetworkError:
return KTcpSocket::NetworkError;
case QAbstractSocket::UnsupportedSocketOperationError:
return KTcpSocket::UnsupportedSocketOperationError;
case QAbstractSocket::DatagramTooLargeError:
//we don't do UDP
case QAbstractSocket::AddressInUseError:
case QAbstractSocket::SocketAddressNotAvailableError:
//### own values if/when we ever get server socket support
case QAbstractSocket::ProxyAuthenticationRequiredError:
//### maybe we need an enum value for this
case QAbstractSocket::UnknownSocketError:
default:
return KTcpSocket::UnknownError;
}
}
//private slots
void reemitSocketError(QAbstractSocket::SocketError e)
{
emit q->error(errorFromAbsSocket(e));
}
void reemitSslErrors(const QList<QSslError> &errors)
{
q->showSslErrors(); //H4X
QList<KSslError> kErrors;
foreach (const QSslError &e, errors) {
kErrors.append(KSslError(e));
}
emit q->sslErrors(kErrors);
}
void reemitStateChanged(QAbstractSocket::SocketState s)
{
emit q->stateChanged(state(s));
}
void reemitModeChanged(QSslSocket::SslMode m)
{
emit q->encryptionModeChanged(encryptionMode(m));
}
// This method is needed because we might emit readyRead() due to this QIODevice
// having some data buffered, so we need to care about blocking, too.
//### useless ATM as readyRead() now just calls d->sock.readyRead().
void reemitReadyRead()
{
if (!emittedReadyRead) {
emittedReadyRead = true;
emit q->readyRead();
emittedReadyRead = false;
}
}
void maybeLoadCertificates()
{
if (!certificatesLoaded) {
sock.setCaCertificates(KSslCertificateManager::self()->caCertificates());
certificatesLoaded = true;
}
}
KTcpSocket *const q;
bool certificatesLoaded;
bool emittedReadyRead;
QSslSocket sock;
QList<KSslCipher> ciphers;
KTcpSocket::SslVersion advertisedSslVersion;
CipherCc ccc;
};
KTcpSocket::KTcpSocket(QObject *parent)
: QIODevice(parent),
d(new KTcpSocketPrivate(this))
{
d->advertisedSslVersion = SslV3;
connect(&d->sock, SIGNAL(aboutToClose()), this, SIGNAL(aboutToClose()));
connect(&d->sock, SIGNAL(bytesWritten(qint64)), this, SIGNAL(bytesWritten(qint64)));
connect(&d->sock, SIGNAL(encryptedBytesWritten(qint64)), this, SIGNAL(encryptedBytesWritten(qint64)));
connect(&d->sock, SIGNAL(readyRead()), this, SLOT(reemitReadyRead()));
connect(&d->sock, SIGNAL(connected()), this, SIGNAL(connected()));
connect(&d->sock, SIGNAL(encrypted()), this, SIGNAL(encrypted()));
connect(&d->sock, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
#ifndef QT_NO_NETWORKPROXY
connect(&d->sock, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)),
this, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
#endif
connect(&d->sock, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(reemitSocketError(QAbstractSocket::SocketError)));
connect(&d->sock, SIGNAL(sslErrors(const QList<QSslError> &)),
this, SLOT(reemitSslErrors(const QList<QSslError> &)));
connect(&d->sock, SIGNAL(hostFound()), this, SIGNAL(hostFound()));
connect(&d->sock, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
this, SLOT(reemitStateChanged(QAbstractSocket::SocketState)));
connect(&d->sock, SIGNAL(modeChanged(QSslSocket::SslMode)),
this, SLOT(reemitModeChanged(QSslSocket::SslMode)));
}
KTcpSocket::~KTcpSocket()
{
delete d;
}
////////////////////////////// (mostly) virtuals from QIODevice
bool KTcpSocket::atEnd() const
{
return d->sock.atEnd() && QIODevice::atEnd();
}
qint64 KTcpSocket::bytesAvailable() const
{
return d->sock.bytesAvailable() + QIODevice::bytesAvailable();
}
qint64 KTcpSocket::bytesToWrite() const
{
return d->sock.bytesToWrite();
}
bool KTcpSocket::canReadLine() const
{
return d->sock.canReadLine() || QIODevice::canReadLine();
}
void KTcpSocket::close()
{
d->sock.close();
QIODevice::close();
}
bool KTcpSocket::isSequential() const
{
return true;
}
bool KTcpSocket::open(QIODevice::OpenMode open)
{
bool ret = d->sock.open(open);
setOpenMode(d->sock.openMode() | QIODevice::Unbuffered);
return ret;
}
bool KTcpSocket::waitForBytesWritten(int msecs)
{
return d->sock.waitForBytesWritten(msecs);
}
bool KTcpSocket::waitForReadyRead(int msecs)
{
return d->sock.waitForReadyRead(msecs);
}
qint64 KTcpSocket::readData(char *data, qint64 maxSize)
{
return d->sock.read(data, maxSize);
}
qint64 KTcpSocket::writeData(const char *data, qint64 maxSize)
{
return d->sock.write(data, maxSize);
}
////////////////////////////// public methods from QAbstractSocket
void KTcpSocket::abort()
{
d->sock.abort();
}
void KTcpSocket::connectToHost(const QString &hostName, quint16 port, ProxyPolicy policy)
{
if (policy == AutoProxy) {
//###
}
d->sock.connectToHost(hostName, port);
// there are enough layers of buffers between us and the network, and there is a quirk
// in QIODevice that can make it try to readData() twice per read() call if buffered and
// reaData() does not deliver enough data the first time. like when the other side is
// simply not sending any more data...
// this can *apparently* lead to long delays sometimes which stalls applications.
// do not want.
setOpenMode(d->sock.openMode() | QIODevice::Unbuffered);
}
void KTcpSocket::connectToHost(const QHostAddress &hostAddress, quint16 port, ProxyPolicy policy)
{
if (policy == AutoProxy) {
//###
}
d->sock.connectToHost(hostAddress, port);
setOpenMode(d->sock.openMode() | QIODevice::Unbuffered);
}
void KTcpSocket::connectToHost(const KUrl &url, ProxyPolicy policy)
{
if (policy == AutoProxy) {
//###
}
d->sock.connectToHost(url.host(), url.port());
setOpenMode(d->sock.openMode() | QIODevice::Unbuffered);
}
void KTcpSocket::disconnectFromHost()
{
d->sock.disconnectFromHost();
setOpenMode(d->sock.openMode() | QIODevice::Unbuffered);
}
KTcpSocket::Error KTcpSocket::error() const
{
return d->errorFromAbsSocket(d->sock.error());
}
QList<KSslError> KTcpSocket::sslErrors() const
{
//### pretty slow; also consider throwing out duplicate error codes. We may get
// duplicates even though there were none in the original list because KSslError
// has a smallest common denominator range of SSL error codes.
QList<KSslError> ret;
foreach (const QSslError &e, d->sock.sslErrors())
ret.append(KSslError(e));
return ret;
}
bool KTcpSocket::flush()
{
return d->sock.flush();
}
bool KTcpSocket::isValid() const
{
return d->sock.isValid();
}
QHostAddress KTcpSocket::localAddress() const
{
return d->sock.localAddress();
}
QHostAddress KTcpSocket::peerAddress() const
{
return d->sock.peerAddress();
}
QString KTcpSocket::peerName() const
{
return d->sock.peerName();
}
quint16 KTcpSocket::peerPort() const
{
return d->sock.peerPort();
}
#ifndef QT_NO_NETWORKPROXY
QNetworkProxy KTcpSocket::proxy() const
{
return d->sock.proxy();
}
#endif
qint64 KTcpSocket::readBufferSize() const
{
return d->sock.readBufferSize();
}
#ifndef QT_NO_NETWORKPROXY
void KTcpSocket::setProxy(const QNetworkProxy &proxy)
{
d->sock.setProxy(proxy);
}
#endif
void KTcpSocket::setReadBufferSize(qint64 size)
{
d->sock.setReadBufferSize(size);
}
KTcpSocket::State KTcpSocket::state() const
{
return d->state(d->sock.state());
}
bool KTcpSocket::waitForConnected(int msecs)
{
bool ret = d->sock.waitForConnected(msecs);
if (!ret)
setErrorString(d->sock.errorString());
setOpenMode(d->sock.openMode() | QIODevice::Unbuffered);
return ret;
}
bool KTcpSocket::waitForDisconnected(int msecs)
{
bool ret = d->sock.waitForDisconnected(msecs);
if (!ret)
setErrorString(d->sock.errorString());
setOpenMode(d->sock.openMode() | QIODevice::Unbuffered);
return ret;
}
////////////////////////////// public methods from QSslSocket
void KTcpSocket::addCaCertificate(const QSslCertificate &certificate)
{
d->maybeLoadCertificates();
d->sock.addCaCertificate(certificate);
}
/*
bool KTcpSocket::addCaCertificates(const QString &path, QSsl::EncodingFormat format,
QRegExp::PatternSyntax syntax)
{
d->maybeLoadCertificates();
return d->sock.addCaCertificates(path, format, syntax);
}
*/
void KTcpSocket::addCaCertificates(const QList<QSslCertificate> &certificates)
{
d->maybeLoadCertificates();
d->sock.addCaCertificates(certificates);
}
QList<QSslCertificate> KTcpSocket::caCertificates() const
{
d->maybeLoadCertificates();
return d->sock.caCertificates();
}
QList<KSslCipher> KTcpSocket::ciphers() const
{
return d->ciphers;
}
void KTcpSocket::connectToHostEncrypted(const QString &hostName, quint16 port, OpenMode openMode)
{
d->maybeLoadCertificates();
d->sock.setProtocol(qSslProtocolFromK(d->advertisedSslVersion));
d->sock.connectToHostEncrypted(hostName, port, openMode);
setOpenMode(d->sock.openMode() | QIODevice::Unbuffered);
}
QSslCertificate KTcpSocket::localCertificate() const
{
return d->sock.localCertificate();
}
QList<QSslCertificate> KTcpSocket::peerCertificateChain() const
{
return d->sock.peerCertificateChain();
}
KSslKey KTcpSocket::privateKey() const
{
return KSslKey(d->sock.privateKey());
}
KSslCipher KTcpSocket::sessionCipher() const
{
return KSslCipher(d->sock.sessionCipher());
}
void KTcpSocket::setCaCertificates(const QList<QSslCertificate> &certificates)
{
d->sock.setCaCertificates(certificates);
d->certificatesLoaded = true;
}
void KTcpSocket::setCiphers(const QList<KSslCipher> &ciphers)
{
d->ciphers = ciphers;
QList<QSslCipher> cl;
foreach (const KSslCipher &c, d->ciphers) {
cl.append(d->ccc.converted(c));
}
d->sock.setCiphers(cl);
}
void KTcpSocket::setLocalCertificate(const QSslCertificate &certificate)
{
d->sock.setLocalCertificate(certificate);
}
void KTcpSocket::setLocalCertificate(const QString &fileName, QSsl::EncodingFormat format)
{
d->sock.setLocalCertificate(fileName, format);
}
void KTcpSocket::setVerificationPeerName(const QString& hostName)
{
#if QT_VERSION >= 0x040800
d->sock.setPeerVerifyName(hostName);
#else
Q_UNUSED(hostName);
#endif
}
//TODO
void KTcpSocket::setPrivateKey(const KSslKey &key)
{
Q_UNUSED(key)
}
//TODO
void KTcpSocket::setPrivateKey(const QString &fileName, KSslKey::Algorithm algorithm,
QSsl::EncodingFormat format, const QByteArray &passPhrase)
{
Q_UNUSED(fileName)
Q_UNUSED(algorithm)
Q_UNUSED(format)
Q_UNUSED(passPhrase)
}
bool KTcpSocket::waitForEncrypted(int msecs)
{
return d->sock.waitForEncrypted(msecs);
}
KTcpSocket::EncryptionMode KTcpSocket::encryptionMode() const
{
return d->encryptionMode(d->sock.mode());
}
QVariant KTcpSocket::socketOption(QAbstractSocket::SocketOption options) const
{
return d->sock.socketOption(options);
}
void KTcpSocket::setSocketOption(QAbstractSocket::SocketOption options, const QVariant &value)
{
d->sock.setSocketOption(options, value);
}
//slot
void KTcpSocket::ignoreSslErrors()
{
d->sock.ignoreSslErrors();
}
//slot
void KTcpSocket::startClientEncryption()
{
d->maybeLoadCertificates();
d->sock.setProtocol(qSslProtocolFromK(d->advertisedSslVersion));
d->sock.startClientEncryption();
}
//debugging H4X
void KTcpSocket::showSslErrors()
{
foreach (const QSslError &e, d->sock.sslErrors())
kDebug(7029) << e.errorString();
}
void KTcpSocket::setAdvertisedSslVersion(KTcpSocket::SslVersion version)
{
d->advertisedSslVersion = version;
}
KTcpSocket::SslVersion KTcpSocket::advertisedSslVersion() const
{
return d->advertisedSslVersion;
}
KTcpSocket::SslVersion KTcpSocket::negotiatedSslVersion() const
{
if (!d->sock.isEncrypted()) {
return UnknownSslVersion;
}
return kSslVersionFromQ(d->sock.protocol());
}
QString KTcpSocket::negotiatedSslVersionName() const
{
if (!d->sock.isEncrypted()) {
return QString();
}
return d->sock.sessionCipher().protocolString();
}
////////////////////////////// KSslKey
class KSslKeyPrivate
{
public:
KSslKey::Algorithm convertAlgorithm(QSsl::KeyAlgorithm a)
{
switch(a) {
case QSsl::Dsa:
return KSslKey::Dsa;
default:
return KSslKey::Rsa;
}
}
KSslKey::Algorithm algorithm;
KSslKey::KeySecrecy secrecy;
bool isExportable;
QByteArray der;
};
KSslKey::KSslKey()
: d(new KSslKeyPrivate)
{
d->algorithm = Rsa;
d->secrecy = PublicKey;
d->isExportable = true;
}
KSslKey::KSslKey(const KSslKey &other)
: d(new KSslKeyPrivate)
{
*d = *other.d;
}
KSslKey::KSslKey(const QSslKey &qsk)
: d(new KSslKeyPrivate)
{
d->algorithm = d->convertAlgorithm(qsk.algorithm());
d->secrecy = (qsk.type() == QSsl::PrivateKey) ? PrivateKey : PublicKey;
d->isExportable = true;
d->der = qsk.toDer();
}
KSslKey::~KSslKey()
{
delete d;
}
KSslKey &KSslKey::operator=(const KSslKey &other)
{
*d = *other.d;
return *this;
}
KSslKey::Algorithm KSslKey::algorithm() const
{
return d->algorithm;
}
bool KSslKey::isExportable() const
{
return d->isExportable;
}
KSslKey::KeySecrecy KSslKey::secrecy() const
{
return d->secrecy;
}
QByteArray KSslKey::toDer() const
{
return d->der;
}
////////////////////////////// KSslCipher
//nice-to-have: make implicitly shared
class KSslCipherPrivate
{
public:
QString authenticationMethod;
QString encryptionMethod;
QString keyExchangeMethod;
QString name;
bool isNull;
int supportedBits;
int usedBits;
};
KSslCipher::KSslCipher()
: d(new KSslCipherPrivate)
{
d->isNull = true;
d->supportedBits = 0;
d->usedBits = 0;
}
KSslCipher::KSslCipher(const KSslCipher &other)
: d(new KSslCipherPrivate)
{
*d = *other.d;
}
KSslCipher::KSslCipher(const QSslCipher &qsc)
: d(new KSslCipherPrivate)
{
d->authenticationMethod = qsc.authenticationMethod();
d->encryptionMethod = qsc.encryptionMethod();
//Qt likes to append the number of bits (usedBits?) to the algorithm,
//for example "AES(256)". We only want the pure algorithm name, though.
int parenIdx = d->encryptionMethod.indexOf(QLatin1Char('('));
if (parenIdx > 0)
d->encryptionMethod.truncate(parenIdx);
d->keyExchangeMethod = qsc.keyExchangeMethod();
d->name = qsc.name();
d->isNull = qsc.isNull();
d->supportedBits = qsc.supportedBits();
d->usedBits = qsc.usedBits();
}
KSslCipher::~KSslCipher()
{
delete d;
}
KSslCipher &KSslCipher::operator=(const KSslCipher &other)
{
*d = *other.d;
return *this;
}
bool KSslCipher::isNull() const
{
return d->isNull;
}
QString KSslCipher::authenticationMethod() const
{
return d->authenticationMethod;
}
QString KSslCipher::encryptionMethod() const
{
return d->encryptionMethod;
}
QString KSslCipher::keyExchangeMethod() const
{
return d->keyExchangeMethod;
}
QString KSslCipher::digestMethod() const
{
//### This is not really backend neutral. It works for OpenSSL and
// for RFC compliant names, though.
if (d->name.endsWith(QLatin1String("SHA")))
return QString::fromLatin1("SHA-1");
else if (d->name.endsWith(QLatin1String("MD5")))
return QString::fromLatin1("MD5");
else
return QString::fromLatin1(""); // ## probably QString() is enough
}
QString KSslCipher::name() const
{
return d->name;
}
int KSslCipher::supportedBits() const
{
return d->supportedBits;
}
int KSslCipher::usedBits() const
{
return d->usedBits;
}
//static
QList<KSslCipher> KSslCipher::supportedCiphers()
{
QList<KSslCipher> ret;
QList<QSslCipher> candidates = QSslSocket::supportedCiphers();
foreach(const QSslCipher &c, candidates) {
ret.append(KSslCipher(c));
}
return ret;
}
KSslErrorUiData::KSslErrorUiData()
: d(new Private())
{
d->usedBits = 0;
d->bits = 0;
}
KSslErrorUiData::KSslErrorUiData(const KTcpSocket *socket)
: d(new Private())
{
d->certificateChain = socket->peerCertificateChain();
d->sslErrors = socket->sslErrors();
d->ip = socket->peerAddress().toString();
d->host = socket->peerName();
d->sslProtocol = socket->negotiatedSslVersionName();
d->cipher = socket->sessionCipher().name();
d->usedBits = socket->sessionCipher().usedBits();
d->bits = socket->sessionCipher().supportedBits();
}
+KSslErrorUiData::KSslErrorUiData(const QSslSocket *socket)
+ : d(new Private())
+{
+ d->certificateChain = socket->peerCertificateChain();
+
+ // See KTcpSocket::sslErrors()
+ foreach (const QSslError &e, socket->sslErrors())
+ d->sslErrors.append(KSslError(e));
+
+ d->ip = socket->peerAddress().toString();
+ d->host = socket->peerName();
+ d->sslProtocol = socket->negotiatedSslVersionName();
+ d->cipher = socket->sessionCipher().name();
+ d->usedBits = socket->sessionCipher().usedBits();
+ d->bits = socket->sessionCipher().supportedBits();
+}
+
KSslErrorUiData::KSslErrorUiData(const KSslErrorUiData &other)
: d(new Private(*other.d))
{}
KSslErrorUiData::~KSslErrorUiData()
{
delete d;
}
KSslErrorUiData &KSslErrorUiData::operator=(const KSslErrorUiData &other)
{
*d = *other.d;
return *this;
}
#include "ktcpsocket.moc"
diff --git a/kdecore/network/ktcpsocket.h b/kdecore/network/ktcpsocket.h
index 3f768ee319..8a9289e3b5 100644
--- a/kdecore/network/ktcpsocket.h
+++ b/kdecore/network/ktcpsocket.h
@@ -1,405 +1,409 @@
/* This file is part of the KDE libraries
Copyright (C) 2007 Thiago Macieira <thiago@kde.org>
Copyright (C) 2007 Andreas Hartmetz <ahartmetz@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KTCPSOCKET_H
#define KTCPSOCKET_H
#include <QtNetwork/QSslSocket>
//#include <QtCore/QRegExp>
#include "kdecore_export.h"
/*
Notes on QCA::TLS compatibility
In order to check for all validation problems as far as possible we need to use:
Validity QCA::TLS::peerCertificateValidity()
TLS::IdentityResult QCA::TLS::peerIdentityResult()
CertificateChain QCA::TLS::peerCertificateChain().validate() - to find the failing cert!
TLS::Error QCA::TLS::errorCode() - for more generic (but stil SSL) errors
*/
class KSslKeyPrivate;
class KDECORE_EXPORT KSslKey {
public:
enum Algorithm {
Rsa = 0,
Dsa,
Dh
};
enum KeySecrecy {
PublicKey,
PrivateKey
};
KSslKey();
KSslKey(const KSslKey &other);
KSslKey(const QSslKey &sslKey);
~KSslKey();
KSslKey &operator=(const KSslKey &other);
Algorithm algorithm() const;
bool isExportable() const;
KeySecrecy secrecy() const;
QByteArray toDer() const;
private:
KSslKeyPrivate *const d;
};
class KSslCipherPrivate;
class KDECORE_EXPORT KSslCipher {
public:
KSslCipher();
KSslCipher(const KSslCipher &other);
KSslCipher(const QSslCipher &);
~KSslCipher();
KSslCipher &operator=(const KSslCipher &other);
bool isNull() const;
QString authenticationMethod() const;
QString encryptionMethod() const;
QString keyExchangeMethod() const;
QString digestMethod() const;
/* mainly for internal use */
QString name() const;
int supportedBits() const;
int usedBits() const;
static QList<KSslCipher> supportedCiphers();
private:
KSslCipherPrivate *const d;
};
class KSslErrorPrivate;
class KTcpSocket;
class KDECORE_EXPORT KSslError
{
public:
enum Error {
NoError = 0,
UnknownError,
InvalidCertificateAuthorityCertificate,
InvalidCertificate,
CertificateSignatureFailed,
SelfSignedCertificate,
ExpiredCertificate,
RevokedCertificate,
InvalidCertificatePurpose,
RejectedCertificate,
UntrustedCertificate,
NoPeerCertificate,
HostNameMismatch,
PathLengthExceeded
};
KSslError(KSslError::Error error = NoError, const QSslCertificate &cert = QSslCertificate());
KSslError(const QSslError &error); //### explicit yes or no?
KSslError(const KSslError &other);
~KSslError();
KSslError &operator=(const KSslError &other);
Error error() const;
QString errorString() const;
QSslCertificate certificate() const;
private:
KSslErrorPrivate *const d;
};
//consider killing more convenience functions with huge signatures
//### do we need setSession() / session() ?
//BIG FAT TODO: do we keep openMode() up to date everywhere it can change?
//other TODO: limit possible error strings?, SSL key stuff
//TODO protocol (or maybe even application?) dependent automatic proxy choice
class KTcpSocketPrivate;
class QHostAddress;
class KUrl;
class KDECORE_EXPORT KTcpSocket: public QIODevice
{
Q_OBJECT
public:
enum State {
UnconnectedState = 0,
HostLookupState,
ConnectingState,
ConnectedState,
BoundState,
ListeningState,
ClosingState
//hmmm, do we need an SslNegotiatingState?
};
enum SslVersion {
UnknownSslVersion = 0x01,
SslV2 = 0x02,
SslV3 = 0x04,
TlsV1 = 0x08,
SslV3_1 = 0x08,
AnySslVersion = SslV2 | SslV3 | TlsV1
};
Q_DECLARE_FLAGS(SslVersions, SslVersion)
enum Error {
UnknownError = 0,
ConnectionRefusedError,
RemoteHostClosedError,
HostNotFoundError,
SocketAccessError,
SocketResourceError,
SocketTimeoutError,
NetworkError,
UnsupportedSocketOperationError
};
/*
The following is based on reading the OpenSSL interface code of both QSslSocket
and QCA::TLS. Barring oversights it should be accurate. The two cases with the
question marks apparently will never be emitted by QSslSocket so there is nothing
to compare.
QSslError::NoError KTcpSocket::NoError
QSslError::UnableToGetIssuerCertificate QCA::ErrorSignatureFailed
QSslError::UnableToDecryptCertificateSignature QCA::ErrorSignatureFailed
QSslError::UnableToDecodeIssuerPublicKey QCA::ErrorInvalidCA
QSslError::CertificateSignatureFailed QCA::ErrorSignatureFailed
QSslError::CertificateNotYetValid QCA::ErrorExpired
QSslError::CertificateExpired QCA::ErrorExpired
QSslError::InvalidNotBeforeField QCA::ErrorExpired
QSslError::InvalidNotAfterField QCA::ErrorExpired
QSslError::SelfSignedCertificate QCA::ErrorSelfSigned
QSslError::SelfSignedCertificateInChain QCA::ErrorSelfSigned
QSslError::UnableToGetLocalIssuerCertificate QCA::ErrorInvalidCA
QSslError::UnableToVerifyFirstCertificate QCA::ErrorSignatureFailed
QSslError::CertificateRevoked QCA::ErrorRevoked
QSslError::InvalidCaCertificate QCA::ErrorInvalidCA
QSslError::PathLengthExceeded QCA::ErrorPathLengthExceeded
QSslError::InvalidPurpose QCA::ErrorInvalidPurpose
QSslError::CertificateUntrusted QCA::ErrorUntrusted
QSslError::CertificateRejected QCA::ErrorRejected
QSslError::SubjectIssuerMismatch QCA::TLS::InvalidCertificate ?
QSslError::AuthorityIssuerSerialNumberMismatch QCA::TLS::InvalidCertificate ?
QSslError::NoPeerCertificate QCA::TLS::NoCertificate
QSslError::HostNameMismatch QCA::TLS::HostMismatch
QSslError::UnspecifiedError KTcpSocket::UnknownError
QSslError::NoSslSupport Never happens :)
*/
enum EncryptionMode {
UnencryptedMode = 0,
SslClientMode,
SslServerMode //### not implemented
};
enum ProxyPolicy {
/// Use the proxy that KProtocolManager suggests for the connection parameters given.
AutoProxy = 0,
/// Use the proxy set by setProxy(), if any; otherwise use no proxy.
ManualProxy
};
KTcpSocket(QObject *parent = 0);
~KTcpSocket();
//from QIODevice
//reimplemented virtuals - the ones not reimplemented are OK for us
virtual bool atEnd() const;
virtual qint64 bytesAvailable() const;
virtual qint64 bytesToWrite() const;
virtual bool canReadLine() const;
virtual void close();
virtual bool isSequential() const;
virtual bool open(QIODevice::OpenMode open);
virtual bool waitForBytesWritten(int msecs);
//### Document that this actually tries to read *more* data
virtual bool waitForReadyRead(int msecs = 30000);
protected:
virtual qint64 readData (char *data, qint64 maxSize);
virtual qint64 writeData (const char *data, qint64 maxSize);
signals:
/// @since 4.8.1
/// Forwarded from QSslSocket
void encryptedBytesWritten( qint64 written );
public:
//from QAbstractSocket
void abort();
void connectToHost(const QString &hostName, quint16 port, ProxyPolicy policy = AutoProxy);
void connectToHost(const QHostAddress &hostAddress, quint16 port, ProxyPolicy policy = AutoProxy);
/**
* Take the hostname and port from @p url and connect to them. The information from a
* full URL enables the most accurate choice of proxy in case of proxy rules that
* depend on high-level information like protocol or username.
* @see KProtocolManager::proxyForUrl()
*/
void connectToHost(const KUrl &url, ProxyPolicy policy = AutoProxy);
void disconnectFromHost();
Error error() const; //### QAbstractSocket's model is strange. error() should be related to the
//current state and *NOT* just report the last error if there was one.
QList<KSslError> sslErrors() const; //### the errors returned can only have a subset of all
//possible QSslError::SslError enum values depending on backend
bool flush();
bool isValid() const;
QHostAddress localAddress() const;
QHostAddress peerAddress() const;
QString peerName() const;
quint16 peerPort() const;
void setVerificationPeerName(const QString& hostName);
#ifndef QT_NO_NETWORKPROXY
/**
* @see: connectToHost()
*/
QNetworkProxy proxy() const;
#endif
qint64 readBufferSize() const; //probably hard to implement correctly
#ifndef QT_NO_NETWORKPROXY
/**
* @see: connectToHost()
*/
void setProxy(const QNetworkProxy &proxy); //people actually seem to need it
#endif
void setReadBufferSize(qint64 size);
State state() const;
bool waitForConnected(int msecs = 30000);
bool waitForDisconnected(int msecs = 30000);
//from QSslSocket
void addCaCertificate(const QSslCertificate &certificate);
// bool addCaCertificates(const QString &path, QSsl::EncodingFormat format = QSsl::Pem,
// QRegExp::PatternSyntax syntax = QRegExp::FixedString);
void addCaCertificates(const QList<QSslCertificate> &certificates);
QList<QSslCertificate> caCertificates() const;
QList<KSslCipher> ciphers() const;
void connectToHostEncrypted(const QString &hostName, quint16 port, OpenMode openMode = ReadWrite);
// bool isEncrypted() const { return encryptionMode() != UnencryptedMode }
QSslCertificate localCertificate() const;
QList<QSslCertificate> peerCertificateChain() const;
KSslKey privateKey() const;
KSslCipher sessionCipher() const;
void setCaCertificates(const QList<QSslCertificate> &certificates);
void setCiphers(const QList<KSslCipher> &ciphers);
//### void setCiphers(const QString &ciphers); //what about i18n?
void setLocalCertificate(const QSslCertificate &certificate);
void setLocalCertificate(const QString &fileName, QSsl::EncodingFormat format = QSsl::Pem);
void setPrivateKey(const KSslKey &key); //implement
void setPrivateKey(const QString &fileName, KSslKey::Algorithm algorithm = KSslKey::Rsa,
QSsl::EncodingFormat format = QSsl::Pem,
const QByteArray &passPhrase = QByteArray()); //TODO
void setAdvertisedSslVersion(SslVersion version);
SslVersion advertisedSslVersion() const; //always equal to last setSslAdvertisedVersion
SslVersion negotiatedSslVersion() const; //negotiated version; downgrades are possible.
QString negotiatedSslVersionName() const;
bool waitForEncrypted(int msecs = 30000);
EncryptionMode encryptionMode() const;
/**
* Returns the state of the socket @p option.
*
* @see QAbstractSocket::socketOption
*
* @since 4.5.0
*/
QVariant socketOption(QAbstractSocket::SocketOption options) const;
/**
- * Sets the socket @p option to @p value.
+ * Sets the socket @p option to @p value.
*
* @see QAbstractSocket::setSocketOption
*
* @since 4.5.0
*/
void setSocketOption(QAbstractSocket::SocketOption options, const QVariant &value);
Q_SIGNALS:
//from QAbstractSocket
void connected();
void disconnected();
void error(KTcpSocket::Error);
void hostFound();
#ifndef QT_NO_NETWORKPROXY
void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator);
#endif
// only for raw socket state, SSL is separate
void stateChanged(KTcpSocket::State);
//from QSslSocket
void encrypted();
void encryptionModeChanged(EncryptionMode);
void sslErrors(const QList<KSslError> &errors);
public Q_SLOTS:
void ignoreSslErrors();
void startClientEncryption();
// void startServerEncryption(); //not implemented
private:
Q_PRIVATE_SLOT(d, void reemitReadyRead())
Q_PRIVATE_SLOT(d, void reemitSocketError(QAbstractSocket::SocketError))
Q_PRIVATE_SLOT(d, void reemitSslErrors(const QList<QSslError> &))
Q_PRIVATE_SLOT(d, void reemitStateChanged(QAbstractSocket::SocketState))
Q_PRIVATE_SLOT(d, void reemitModeChanged(QSslSocket::SslMode))
//debugging H4X
void showSslErrors();
friend class KTcpSocketPrivate;
KTcpSocketPrivate *const d;
};
/**
* This class can hold all the necessary data from a KTcpSocket to ask the user
* to continue connecting in the face of SSL errors.
* It can be used to carry the data for the UI over time or over thread boundaries.
*
* @see: KSslCertificateManager::askIgnoreSslErrors()
*/
class KDECORE_EXPORT KSslErrorUiData
{
public:
/**
* Default construct an instance with no useful data.
*/
KSslErrorUiData();
/**
* Create an instance and initialize it with SSL error data from @p socket.
*/
KSslErrorUiData(const KTcpSocket *socket);
+ /**
+ * Create an instance and initialize it with SSL error data from @p socket.
+ */
+ KSslErrorUiData(const QSslSocket *socket);
KSslErrorUiData(const KSslErrorUiData &other);
KSslErrorUiData &operator=(const KSslErrorUiData &);
/**
* Destructor
* @since 4.7
*/
~KSslErrorUiData();
class Private;
private:
friend class Private;
Private *const d;
};
#endif // KTCPSOCKET_H

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 1, 8:42 AM (1 d, 10 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
10075197
Default Alt Text
(43 KB)

Event Timeline