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 | |
39 | class KSslKeyPrivate; |
40 | |
41 | class KDECORE_EXPORT KSslKey { |
42 | public: |
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; |
63 | private: |
64 | KSslKeyPrivate *const d; |
65 | }; |
66 | |
67 | |
68 | class KSslCipherPrivate; |
69 | |
70 | class KDECORE_EXPORT KSslCipher { |
71 | public: |
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 | |
90 | private: |
91 | KSslCipherPrivate *const d; |
92 | }; |
93 | |
94 | |
95 | class KSslErrorPrivate; |
96 | class KTcpSocket; |
97 | |
98 | class KDECORE_EXPORT KSslError |
99 | { |
100 | public: |
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; |
126 | private: |
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 | |
140 | class KTcpSocketPrivate; |
141 | class QHostAddress; |
142 | class KUrl; |
143 | |
144 | class KDECORE_EXPORT KTcpSocket: public QIODevice |
145 | { |
146 | Q_OBJECT |
147 | public: |
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 | /* |
182 | The following is based on reading the OpenSSL interface code of both QSslSocket |
183 | and QCA::TLS. Barring oversights it should be accurate. The two cases with the |
184 | question marks apparently will never be emitted by QSslSocket so there is nothing |
185 | to compare. |
186 | |
187 | QSslError::NoError KTcpSocket::NoError |
188 | QSslError::UnableToGetIssuerCertificate QCA::ErrorSignatureFailed |
189 | QSslError::UnableToDecryptCertificateSignature QCA::ErrorSignatureFailed |
190 | QSslError::UnableToDecodeIssuerPublicKey QCA::ErrorInvalidCA |
191 | QSslError::CertificateSignatureFailed QCA::ErrorSignatureFailed |
192 | QSslError::CertificateNotYetValid QCA::ErrorExpired |
193 | QSslError::CertificateExpired QCA::ErrorExpired |
194 | QSslError::InvalidNotBeforeField QCA::ErrorExpired |
195 | QSslError::InvalidNotAfterField QCA::ErrorExpired |
196 | QSslError::SelfSignedCertificate QCA::ErrorSelfSigned |
197 | QSslError::SelfSignedCertificateInChain QCA::ErrorSelfSigned |
198 | QSslError::UnableToGetLocalIssuerCertificate QCA::ErrorInvalidCA |
199 | QSslError::UnableToVerifyFirstCertificate QCA::ErrorSignatureFailed |
200 | QSslError::CertificateRevoked QCA::ErrorRevoked |
201 | QSslError::InvalidCaCertificate QCA::ErrorInvalidCA |
202 | QSslError::PathLengthExceeded QCA::ErrorPathLengthExceeded |
203 | QSslError::InvalidPurpose QCA::ErrorInvalidPurpose |
204 | QSslError::CertificateUntrusted QCA::ErrorUntrusted |
205 | QSslError::CertificateRejected QCA::ErrorRejected |
206 | QSslError::SubjectIssuerMismatch QCA::TLS::InvalidCertificate ? |
207 | QSslError::AuthorityIssuerSerialNumberMismatch QCA::TLS::InvalidCertificate ? |
208 | QSslError::NoPeerCertificate QCA::TLS::NoCertificate |
209 | QSslError::HostNameMismatch QCA::TLS::HostMismatch |
210 | QSslError::UnspecifiedError KTcpSocket::UnknownError |
211 | QSslError::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); |
240 | protected: |
241 | virtual qint64 readData (char *data, qint64 maxSize); |
242 | virtual qint64 writeData (const char *data, qint64 maxSize); |
243 | Q_SIGNALS: |
244 | /// @since 4.8.1 |
245 | /// Forwarded from QSslSocket |
246 | void encryptedBytesWritten( qint64 written ); |
247 | public: |
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 | |
354 | Q_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 | |
371 | public Q_SLOTS: |
372 | void ignoreSslErrors(); |
373 | void startClientEncryption(); |
374 | // void startServerEncryption(); //not implemented |
375 | private: |
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 | */ |
397 | class KDECORE_EXPORT KSslErrorUiData |
398 | { |
399 | public: |
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; |
420 | private: |
421 | friend class Private; |
422 | Private *const d; |
423 | }; |
424 | |
425 | |
426 | #endif // KTCPSOCKET_H |
427 | |