mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-24 19:02:48 +00:00
427 lines
14 KiB
C
427 lines
14 KiB
C
![]() |
/* 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 <QtNetwork/QSslConfiguration>
|
||
|
|
||
|
#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,
|
||
|
TlsV1SslV3 = 0x10,
|
||
|
SecureProtocols = 0x20,
|
||
|
AnySslVersion = SslV2 | SslV3 | TlsV1
|
||
|
};
|
||
|
Q_DECLARE_FLAGS(SslVersions, SslVersion)
|
||
|
enum Error {
|
||
|
UnknownError = 0,
|
||
|
ConnectionRefusedError,
|
||
|
RemoteHostClosedError,
|
||
|
HostNotFoundError,
|
||
|
SocketAccessError,
|
||
|
SocketResourceError,
|
||
|
SocketTimeoutError,
|
||
|
NetworkError,
|
||
|
UnsupportedSocketOperationError,
|
||
|
SslHandshakeFailedError ///< @since 4.10.5
|
||
|
};
|
||
|
/*
|
||
|
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);
|
||
|
Q_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);
|
||
|
void setPrivateKey(const QString &fileName, KSslKey::Algorithm algorithm = KSslKey::Rsa,
|
||
|
QSsl::EncodingFormat format = QSsl::Pem,
|
||
|
const QByteArray &passPhrase = QByteArray());
|
||
|
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.
|
||
|
*
|
||
|
* @see QAbstractSocket::setSocketOption
|
||
|
*
|
||
|
* @since 4.5.0
|
||
|
*/
|
||
|
void setSocketOption(QAbstractSocket::SocketOption options, const QVariant &value);
|
||
|
|
||
|
/**
|
||
|
* Returns the socket's SSL configuration.
|
||
|
*
|
||
|
* @since 4.8.4
|
||
|
*/
|
||
|
QSslConfiguration sslConfiguration() const;
|
||
|
|
||
|
/**
|
||
|
* Sets the socket's SSL configuration.
|
||
|
*
|
||
|
* @since 4.8.4
|
||
|
*/
|
||
|
void setSslConfiguration(const QSslConfiguration& configuration);
|
||
|
|
||
|
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
|