1/* This file is part of the KDE libraries
2 Copyright (C) 2007 Thiago Macieira <thiago@kde.org>
3 Copyright (C) 2007 Andreas Hartmetz <ahartmetz@gmail.com>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21#ifndef KTCPSOCKET_H
22#define KTCPSOCKET_H
23
24#include <QtNetwork/QSslSocket>
25#include <QtNetwork/QSslConfiguration>
26
27#include "kdecore_export.h"
28
29/*
30 Notes on QCA::TLS compatibility
31 In order to check for all validation problems as far as possible we need to use:
32 Validity QCA::TLS::peerCertificateValidity()
33 TLS::IdentityResult QCA::TLS::peerIdentityResult()
34 CertificateChain QCA::TLS::peerCertificateChain().validate() - to find the failing cert!
35 TLS::Error QCA::TLS::errorCode() - for more generic (but stil SSL) errors
36 */
37
38
39class KSslKeyPrivate;
40
41class KDECORE_EXPORT KSslKey {
42public:
43 enum Algorithm {
44 Rsa = 0,
45 Dsa,
46 Dh
47 };
48 enum KeySecrecy {
49 PublicKey,
50 PrivateKey
51 };
52
53 KSslKey();
54 KSslKey(const KSslKey &other);
55 KSslKey(const QSslKey &sslKey);
56 ~KSslKey();
57 KSslKey &operator=(const KSslKey &other);
58
59 Algorithm algorithm() const;
60 bool isExportable() const;
61 KeySecrecy secrecy() const;
62 QByteArray toDer() const;
63private:
64 KSslKeyPrivate *const d;
65};
66
67
68class KSslCipherPrivate;
69
70class KDECORE_EXPORT KSslCipher {
71public:
72 KSslCipher();
73 KSslCipher(const KSslCipher &other);
74 KSslCipher(const QSslCipher &);
75 ~KSslCipher();
76 KSslCipher &operator=(const KSslCipher &other);
77
78 bool isNull() const;
79 QString authenticationMethod() const;
80 QString encryptionMethod() const;
81 QString keyExchangeMethod() const;
82 QString digestMethod() const;
83 /* mainly for internal use */
84 QString name() const;
85 int supportedBits() const;
86 int usedBits() const;
87
88 static QList<KSslCipher> supportedCiphers();
89
90private:
91 KSslCipherPrivate *const d;
92};
93
94
95class KSslErrorPrivate;
96class KTcpSocket;
97
98class KDECORE_EXPORT KSslError
99{
100public:
101 enum Error {
102 NoError = 0,
103 UnknownError,
104 InvalidCertificateAuthorityCertificate,
105 InvalidCertificate,
106 CertificateSignatureFailed,
107 SelfSignedCertificate,
108 ExpiredCertificate,
109 RevokedCertificate,
110 InvalidCertificatePurpose,
111 RejectedCertificate,
112 UntrustedCertificate,
113 NoPeerCertificate,
114 HostNameMismatch,
115 PathLengthExceeded
116 };
117 KSslError(KSslError::Error error = NoError, const QSslCertificate &cert = QSslCertificate());
118 KSslError(const QSslError &error); //### explicit yes or no?
119 KSslError(const KSslError &other);
120 ~KSslError();
121 KSslError &operator=(const KSslError &other);
122
123 Error error() const;
124 QString errorString() const;
125 QSslCertificate certificate() const;
126private:
127 KSslErrorPrivate *const d;
128};
129
130
131//consider killing more convenience functions with huge signatures
132//### do we need setSession() / session() ?
133
134//BIG FAT TODO: do we keep openMode() up to date everywhere it can change?
135
136//other TODO: limit possible error strings?, SSL key stuff
137
138//TODO protocol (or maybe even application?) dependent automatic proxy choice
139
140class KTcpSocketPrivate;
141class QHostAddress;
142class KUrl;
143
144class KDECORE_EXPORT KTcpSocket: public QIODevice
145{
146 Q_OBJECT
147public:
148 enum State {
149 UnconnectedState = 0,
150 HostLookupState,
151 ConnectingState,
152 ConnectedState,
153 BoundState,
154 ListeningState,
155 ClosingState
156 //hmmm, do we need an SslNegotiatingState?
157 };
158 enum SslVersion {
159 UnknownSslVersion = 0x01,
160 SslV2 = 0x02,
161 SslV3 = 0x04,
162 TlsV1 = 0x08,
163 SslV3_1 = 0x08,
164 TlsV1SslV3 = 0x10,
165 SecureProtocols = 0x20,
166 AnySslVersion = SslV2 | SslV3 | TlsV1
167 };
168 Q_DECLARE_FLAGS(SslVersions, SslVersion)
169 enum Error {
170 UnknownError = 0,
171 ConnectionRefusedError,
172 RemoteHostClosedError,
173 HostNotFoundError,
174 SocketAccessError,
175 SocketResourceError,
176 SocketTimeoutError,
177 NetworkError,
178 UnsupportedSocketOperationError,
179 SslHandshakeFailedError ///< @since 4.10.5
180 };
181/*
182The following is based on reading the OpenSSL interface code of both QSslSocket
183and QCA::TLS. Barring oversights it should be accurate. The two cases with the
184question marks apparently will never be emitted by QSslSocket so there is nothing
185to compare.
186
187QSslError::NoError KTcpSocket::NoError
188QSslError::UnableToGetIssuerCertificate QCA::ErrorSignatureFailed
189QSslError::UnableToDecryptCertificateSignature QCA::ErrorSignatureFailed
190QSslError::UnableToDecodeIssuerPublicKey QCA::ErrorInvalidCA
191QSslError::CertificateSignatureFailed QCA::ErrorSignatureFailed
192QSslError::CertificateNotYetValid QCA::ErrorExpired
193QSslError::CertificateExpired QCA::ErrorExpired
194QSslError::InvalidNotBeforeField QCA::ErrorExpired
195QSslError::InvalidNotAfterField QCA::ErrorExpired
196QSslError::SelfSignedCertificate QCA::ErrorSelfSigned
197QSslError::SelfSignedCertificateInChain QCA::ErrorSelfSigned
198QSslError::UnableToGetLocalIssuerCertificate QCA::ErrorInvalidCA
199QSslError::UnableToVerifyFirstCertificate QCA::ErrorSignatureFailed
200QSslError::CertificateRevoked QCA::ErrorRevoked
201QSslError::InvalidCaCertificate QCA::ErrorInvalidCA
202QSslError::PathLengthExceeded QCA::ErrorPathLengthExceeded
203QSslError::InvalidPurpose QCA::ErrorInvalidPurpose
204QSslError::CertificateUntrusted QCA::ErrorUntrusted
205QSslError::CertificateRejected QCA::ErrorRejected
206QSslError::SubjectIssuerMismatch QCA::TLS::InvalidCertificate ?
207QSslError::AuthorityIssuerSerialNumberMismatch QCA::TLS::InvalidCertificate ?
208QSslError::NoPeerCertificate QCA::TLS::NoCertificate
209QSslError::HostNameMismatch QCA::TLS::HostMismatch
210QSslError::UnspecifiedError KTcpSocket::UnknownError
211QSslError::NoSslSupport Never happens :)
212 */
213 enum EncryptionMode {
214 UnencryptedMode = 0,
215 SslClientMode,
216 SslServerMode //### not implemented
217 };
218 enum ProxyPolicy {
219 /// Use the proxy that KProtocolManager suggests for the connection parameters given.
220 AutoProxy = 0,
221 /// Use the proxy set by setProxy(), if any; otherwise use no proxy.
222 ManualProxy
223 };
224
225 KTcpSocket(QObject *parent = 0);
226 ~KTcpSocket();
227
228 //from QIODevice
229 //reimplemented virtuals - the ones not reimplemented are OK for us
230 virtual bool atEnd() const;
231 virtual qint64 bytesAvailable() const;
232 virtual qint64 bytesToWrite() const;
233 virtual bool canReadLine() const;
234 virtual void close();
235 virtual bool isSequential() const;
236 virtual bool open(QIODevice::OpenMode open);
237 virtual bool waitForBytesWritten(int msecs);
238 //### Document that this actually tries to read *more* data
239 virtual bool waitForReadyRead(int msecs = 30000);
240protected:
241 virtual qint64 readData (char *data, qint64 maxSize);
242 virtual qint64 writeData (const char *data, qint64 maxSize);
243Q_SIGNALS:
244 /// @since 4.8.1
245 /// Forwarded from QSslSocket
246 void encryptedBytesWritten( qint64 written );
247public:
248 //from QAbstractSocket
249 void abort();
250 void connectToHost(const QString &hostName, quint16 port, ProxyPolicy policy = AutoProxy);
251 void connectToHost(const QHostAddress &hostAddress, quint16 port, ProxyPolicy policy = AutoProxy);
252
253 /**
254 * Take the hostname and port from @p url and connect to them. The information from a
255 * full URL enables the most accurate choice of proxy in case of proxy rules that
256 * depend on high-level information like protocol or username.
257 * @see KProtocolManager::proxyForUrl()
258 */
259 void connectToHost(const KUrl &url, ProxyPolicy policy = AutoProxy);
260 void disconnectFromHost();
261 Error error() const; //### QAbstractSocket's model is strange. error() should be related to the
262 //current state and *NOT* just report the last error if there was one.
263 QList<KSslError> sslErrors() const; //### the errors returned can only have a subset of all
264 //possible QSslError::SslError enum values depending on backend
265 bool flush();
266 bool isValid() const;
267 QHostAddress localAddress() const;
268 QHostAddress peerAddress() const;
269 QString peerName() const;
270 quint16 peerPort() const;
271 void setVerificationPeerName(const QString& hostName);
272
273#ifndef QT_NO_NETWORKPROXY
274 /**
275 * @see: connectToHost()
276 */
277 QNetworkProxy proxy() const;
278#endif
279 qint64 readBufferSize() const; //probably hard to implement correctly
280
281#ifndef QT_NO_NETWORKPROXY
282 /**
283 * @see: connectToHost()
284 */
285 void setProxy(const QNetworkProxy &proxy); //people actually seem to need it
286#endif
287 void setReadBufferSize(qint64 size);
288 State state() const;
289 bool waitForConnected(int msecs = 30000);
290 bool waitForDisconnected(int msecs = 30000);
291
292 //from QSslSocket
293 void addCaCertificate(const QSslCertificate &certificate);
294// bool addCaCertificates(const QString &path, QSsl::EncodingFormat format = QSsl::Pem,
295// QRegExp::PatternSyntax syntax = QRegExp::FixedString);
296 void addCaCertificates(const QList<QSslCertificate> &certificates);
297 QList<QSslCertificate> caCertificates() const;
298 QList<KSslCipher> ciphers() const;
299 void connectToHostEncrypted(const QString &hostName, quint16 port, OpenMode openMode = ReadWrite);
300 // bool isEncrypted() const { return encryptionMode() != UnencryptedMode }
301 QSslCertificate localCertificate() const;
302 QList<QSslCertificate> peerCertificateChain() const;
303 KSslKey privateKey() const;
304 KSslCipher sessionCipher() const;
305 void setCaCertificates(const QList<QSslCertificate> &certificates);
306 void setCiphers(const QList<KSslCipher> &ciphers);
307 //### void setCiphers(const QString &ciphers); //what about i18n?
308 void setLocalCertificate(const QSslCertificate &certificate);
309 void setLocalCertificate(const QString &fileName, QSsl::EncodingFormat format = QSsl::Pem);
310 void setPrivateKey(const KSslKey &key);
311 void setPrivateKey(const QString &fileName, KSslKey::Algorithm algorithm = KSslKey::Rsa,
312 QSsl::EncodingFormat format = QSsl::Pem,
313 const QByteArray &passPhrase = QByteArray());
314 void setAdvertisedSslVersion(SslVersion version);
315 SslVersion advertisedSslVersion() const; //always equal to last setSslAdvertisedVersion
316 SslVersion negotiatedSslVersion() const; //negotiated version; downgrades are possible.
317 QString negotiatedSslVersionName() const;
318 bool waitForEncrypted(int msecs = 30000);
319
320 EncryptionMode encryptionMode() const;
321
322 /**
323 * Returns the state of the socket @p option.
324 *
325 * @see QAbstractSocket::socketOption
326 *
327 * @since 4.5.0
328 */
329 QVariant socketOption(QAbstractSocket::SocketOption options) const;
330
331 /**
332 * Sets the socket @p option to @p value.
333 *
334 * @see QAbstractSocket::setSocketOption
335 *
336 * @since 4.5.0
337 */
338 void setSocketOption(QAbstractSocket::SocketOption options, const QVariant &value);
339
340 /**
341 * Returns the socket's SSL configuration.
342 *
343 * @since 4.8.4
344 */
345 QSslConfiguration sslConfiguration() const;
346
347 /**
348 * Sets the socket's SSL configuration.
349 *
350 * @since 4.8.4
351 */
352 void setSslConfiguration(const QSslConfiguration& configuration);
353
354Q_SIGNALS:
355 //from QAbstractSocket
356 void connected();
357 void disconnected();
358 void error(KTcpSocket::Error);
359 void hostFound();
360#ifndef QT_NO_NETWORKPROXY
361 void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator);
362#endif
363 // only for raw socket state, SSL is separate
364 void stateChanged(KTcpSocket::State);
365
366 //from QSslSocket
367 void encrypted();
368 void encryptionModeChanged(EncryptionMode);
369 void sslErrors(const QList<KSslError> &errors);
370
371public Q_SLOTS:
372 void ignoreSslErrors();
373 void startClientEncryption();
374 // void startServerEncryption(); //not implemented
375private:
376 Q_PRIVATE_SLOT(d, void reemitReadyRead())
377 Q_PRIVATE_SLOT(d, void reemitSocketError(QAbstractSocket::SocketError))
378 Q_PRIVATE_SLOT(d, void reemitSslErrors(const QList<QSslError> &))
379 Q_PRIVATE_SLOT(d, void reemitStateChanged(QAbstractSocket::SocketState))
380 Q_PRIVATE_SLOT(d, void reemitModeChanged(QSslSocket::SslMode))
381
382//debugging H4X
383 void showSslErrors();
384
385 friend class KTcpSocketPrivate;
386 KTcpSocketPrivate *const d;
387};
388
389
390/**
391 * This class can hold all the necessary data from a KTcpSocket to ask the user
392 * to continue connecting in the face of SSL errors.
393 * It can be used to carry the data for the UI over time or over thread boundaries.
394 *
395 * @see: KSslCertificateManager::askIgnoreSslErrors()
396 */
397class KDECORE_EXPORT KSslErrorUiData
398{
399public:
400 /**
401 * Default construct an instance with no useful data.
402 */
403 KSslErrorUiData();
404 /**
405 * Create an instance and initialize it with SSL error data from @p socket.
406 */
407 KSslErrorUiData(const KTcpSocket *socket);
408 /**
409 * Create an instance and initialize it with SSL error data from @p socket.
410 */
411 KSslErrorUiData(const QSslSocket *socket);
412 KSslErrorUiData(const KSslErrorUiData &other);
413 KSslErrorUiData &operator=(const KSslErrorUiData &);
414 /**
415 * Destructor
416 * @since 4.7
417 */
418 ~KSslErrorUiData();
419 class Private;
420private:
421 friend class Private;
422 Private *const d;
423};
424
425
426#endif // KTCPSOCKET_H
427