Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F16569708
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
43 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
rKL kdelibs
Attached
Detach File
Event Timeline
Log In to Comment