|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtNetwork module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 //#define QSSLSOCKET_DEBUG |
|
43 |
|
44 #include "qsslsocket_openssl_p.h" |
|
45 #include "qsslsocket_openssl_symbols_p.h" |
|
46 #include "qsslsocket.h" |
|
47 #include "qsslcertificate_p.h" |
|
48 #include "qsslcipher_p.h" |
|
49 |
|
50 #include <QtCore/qdatetime.h> |
|
51 #include <QtCore/qdebug.h> |
|
52 #include <QtCore/qdir.h> |
|
53 #include <QtCore/qdiriterator.h> |
|
54 #include <QtCore/qfile.h> |
|
55 #include <QtCore/qfileinfo.h> |
|
56 #include <QtCore/qmutex.h> |
|
57 #include <QtCore/qthread.h> |
|
58 #include <QtCore/qurl.h> |
|
59 #include <QtCore/qvarlengtharray.h> |
|
60 |
|
61 static void initNetworkResources() |
|
62 { |
|
63 // Initialize resources |
|
64 Q_INIT_RESOURCE(network); |
|
65 } |
|
66 |
|
67 QT_BEGIN_NAMESPACE |
|
68 |
|
69 // Useful defines |
|
70 #define SSL_ERRORSTR() QString::fromLocal8Bit(q_ERR_error_string(q_ERR_get_error(), NULL)) |
|
71 |
|
72 /* \internal |
|
73 |
|
74 From OpenSSL's thread(3) manual page: |
|
75 |
|
76 OpenSSL can safely be used in multi-threaded applications provided that at |
|
77 least two callback functions are set. |
|
78 |
|
79 locking_function(int mode, int n, const char *file, int line) is needed to |
|
80 perform locking on shared data structures. (Note that OpenSSL uses a |
|
81 number of global data structures that will be implicitly shared |
|
82 when-whenever ever multiple threads use OpenSSL.) Multi-threaded |
|
83 applications will crash at random if it is not set. ... |
|
84 ... |
|
85 id_function(void) is a function that returns a thread ID. It is not |
|
86 needed on Windows nor on platforms where getpid() returns a different |
|
87 ID for each thread (most notably Linux) |
|
88 */ |
|
89 class QOpenSslLocks |
|
90 { |
|
91 public: |
|
92 inline QOpenSslLocks() |
|
93 : initLocker(QMutex::Recursive), |
|
94 locksLocker(QMutex::Recursive) |
|
95 { |
|
96 QMutexLocker locker(&locksLocker); |
|
97 int numLocks = q_CRYPTO_num_locks(); |
|
98 locks = new QMutex *[numLocks]; |
|
99 memset(locks, 0, numLocks * sizeof(QMutex *)); |
|
100 } |
|
101 inline ~QOpenSslLocks() |
|
102 { |
|
103 QMutexLocker locker(&locksLocker); |
|
104 for (int i = 0; i < q_CRYPTO_num_locks(); ++i) |
|
105 delete locks[i]; |
|
106 delete [] locks; |
|
107 |
|
108 QSslSocketPrivate::deinitialize(); |
|
109 } |
|
110 inline QMutex *lock(int num) |
|
111 { |
|
112 QMutexLocker locker(&locksLocker); |
|
113 QMutex *tmp = locks[num]; |
|
114 if (!tmp) |
|
115 tmp = locks[num] = new QMutex(QMutex::Recursive); |
|
116 return tmp; |
|
117 } |
|
118 |
|
119 QMutex *globalLock() |
|
120 { |
|
121 return &locksLocker; |
|
122 } |
|
123 |
|
124 QMutex *initLock() |
|
125 { |
|
126 return &initLocker; |
|
127 } |
|
128 |
|
129 private: |
|
130 QMutex initLocker; |
|
131 QMutex locksLocker; |
|
132 QMutex **locks; |
|
133 }; |
|
134 Q_GLOBAL_STATIC(QOpenSslLocks, openssl_locks) |
|
135 |
|
136 extern "C" { |
|
137 static void locking_function(int mode, int lockNumber, const char *, int) |
|
138 { |
|
139 QMutex *mutex = openssl_locks()->lock(lockNumber); |
|
140 |
|
141 // Lock or unlock it |
|
142 if (mode & CRYPTO_LOCK) |
|
143 mutex->lock(); |
|
144 else |
|
145 mutex->unlock(); |
|
146 } |
|
147 static unsigned long id_function() |
|
148 { |
|
149 return (unsigned long)QThread::currentThreadId(); |
|
150 } |
|
151 } // extern "C" |
|
152 |
|
153 QSslSocketBackendPrivate::QSslSocketBackendPrivate() |
|
154 : ssl(0), |
|
155 ctx(0), |
|
156 readBio(0), |
|
157 writeBio(0), |
|
158 session(0) |
|
159 { |
|
160 // Calls SSL_library_init(). |
|
161 ensureInitialized(); |
|
162 } |
|
163 |
|
164 QSslSocketBackendPrivate::~QSslSocketBackendPrivate() |
|
165 { |
|
166 } |
|
167 |
|
168 QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(SSL_CIPHER *cipher) |
|
169 { |
|
170 QSslCipher ciph; |
|
171 |
|
172 char buf [256]; |
|
173 QString descriptionOneLine = QString::fromLatin1(q_SSL_CIPHER_description(cipher, buf, sizeof(buf))); |
|
174 |
|
175 QStringList descriptionList = descriptionOneLine.split(QLatin1String(" "), QString::SkipEmptyParts); |
|
176 if (descriptionList.size() > 5) { |
|
177 // ### crude code. |
|
178 ciph.d->isNull = false; |
|
179 ciph.d->name = descriptionList.at(0); |
|
180 |
|
181 QString protoString = descriptionList.at(1); |
|
182 ciph.d->protocolString = protoString; |
|
183 ciph.d->protocol = QSsl::UnknownProtocol; |
|
184 if (protoString == QLatin1String("SSLv3")) |
|
185 ciph.d->protocol = QSsl::SslV3; |
|
186 else if (protoString == QLatin1String("SSLv2")) |
|
187 ciph.d->protocol = QSsl::SslV2; |
|
188 else if (protoString == QLatin1String("TLSv1")) |
|
189 ciph.d->protocol = QSsl::TlsV1; |
|
190 |
|
191 if (descriptionList.at(2).startsWith(QLatin1String("Kx="))) |
|
192 ciph.d->keyExchangeMethod = descriptionList.at(2).mid(3); |
|
193 if (descriptionList.at(3).startsWith(QLatin1String("Au="))) |
|
194 ciph.d->authenticationMethod = descriptionList.at(3).mid(3); |
|
195 if (descriptionList.at(4).startsWith(QLatin1String("Enc="))) |
|
196 ciph.d->encryptionMethod = descriptionList.at(4).mid(4); |
|
197 ciph.d->exportable = (descriptionList.size() > 6 && descriptionList.at(6) == QLatin1String("export")); |
|
198 |
|
199 ciph.d->bits = cipher->strength_bits; |
|
200 ciph.d->supportedBits = cipher->alg_bits; |
|
201 |
|
202 } |
|
203 return ciph; |
|
204 } |
|
205 |
|
206 // ### This list is shared between all threads, and protected by a |
|
207 // mutex. Investigate using thread local storage instead. |
|
208 struct QSslErrorList |
|
209 { |
|
210 QMutex mutex; |
|
211 QList<QPair<int, int> > errors; |
|
212 }; |
|
213 Q_GLOBAL_STATIC(QSslErrorList, _q_sslErrorList) |
|
214 static int q_X509Callback(int ok, X509_STORE_CTX *ctx) |
|
215 { |
|
216 if (!ok) { |
|
217 // Store the error and at which depth the error was detected. |
|
218 _q_sslErrorList()->errors << qMakePair<int, int>(ctx->error, ctx->error_depth); |
|
219 } |
|
220 // Always return OK to allow verification to continue. We're handle the |
|
221 // errors gracefully after collecting all errors, after verification has |
|
222 // completed. |
|
223 return 1; |
|
224 } |
|
225 |
|
226 bool QSslSocketBackendPrivate::initSslContext() |
|
227 { |
|
228 Q_Q(QSslSocket); |
|
229 |
|
230 // Create and initialize SSL context. Accept SSLv2, SSLv3 and TLSv1. |
|
231 bool client = (mode == QSslSocket::SslClientMode); |
|
232 |
|
233 bool reinitialized = false; |
|
234 init_context: |
|
235 switch (configuration.protocol) { |
|
236 case QSsl::SslV2: |
|
237 ctx = q_SSL_CTX_new(client ? q_SSLv2_client_method() : q_SSLv2_server_method()); |
|
238 break; |
|
239 case QSsl::SslV3: |
|
240 ctx = q_SSL_CTX_new(client ? q_SSLv3_client_method() : q_SSLv3_server_method()); |
|
241 break; |
|
242 case QSsl::AnyProtocol: |
|
243 default: |
|
244 ctx = q_SSL_CTX_new(client ? q_SSLv23_client_method() : q_SSLv23_server_method()); |
|
245 break; |
|
246 case QSsl::TlsV1: |
|
247 ctx = q_SSL_CTX_new(client ? q_TLSv1_client_method() : q_TLSv1_server_method()); |
|
248 break; |
|
249 } |
|
250 if (!ctx) { |
|
251 // After stopping Flash 10 the SSL library looses its ciphers. Try re-adding them |
|
252 // by re-initializing the library. |
|
253 if (!reinitialized) { |
|
254 reinitialized = true; |
|
255 if (q_SSL_library_init() == 1) |
|
256 goto init_context; |
|
257 } |
|
258 |
|
259 // ### Bad error code |
|
260 q->setErrorString(QSslSocket::tr("Error creating SSL context (%1)").arg(SSL_ERRORSTR())); |
|
261 q->setSocketError(QAbstractSocket::UnknownSocketError); |
|
262 emit q->error(QAbstractSocket::UnknownSocketError); |
|
263 return false; |
|
264 } |
|
265 |
|
266 // Enable all bug workarounds. |
|
267 q_SSL_CTX_set_options(ctx, SSL_OP_ALL); |
|
268 |
|
269 // Initialize ciphers |
|
270 QByteArray cipherString; |
|
271 int first = true; |
|
272 QList<QSslCipher> ciphers = configuration.ciphers; |
|
273 if (ciphers.isEmpty()) |
|
274 ciphers = defaultCiphers(); |
|
275 foreach (const QSslCipher &cipher, ciphers) { |
|
276 if (first) |
|
277 first = false; |
|
278 else |
|
279 cipherString.append(':'); |
|
280 cipherString.append(cipher.name().toLatin1()); |
|
281 } |
|
282 |
|
283 if (!q_SSL_CTX_set_cipher_list(ctx, cipherString.data())) { |
|
284 // ### Bad error code |
|
285 q->setErrorString(QSslSocket::tr("Invalid or empty cipher list (%1)").arg(SSL_ERRORSTR())); |
|
286 q->setSocketError(QAbstractSocket::UnknownSocketError); |
|
287 emit q->error(QAbstractSocket::UnknownSocketError); |
|
288 return false; |
|
289 } |
|
290 |
|
291 // Add all our CAs to this store. |
|
292 foreach (const QSslCertificate &caCertificate, q->caCertificates()) |
|
293 q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle()); |
|
294 |
|
295 // Register a custom callback to get all verification errors. |
|
296 X509_STORE_set_verify_cb_func(ctx->cert_store, q_X509Callback); |
|
297 |
|
298 if (!configuration.localCertificate.isNull()) { |
|
299 // Require a private key as well. |
|
300 if (configuration.privateKey.isNull()) { |
|
301 q->setErrorString(QSslSocket::tr("Cannot provide a certificate with no key, %1").arg(SSL_ERRORSTR())); |
|
302 emit q->error(QAbstractSocket::UnknownSocketError); |
|
303 return false; |
|
304 } |
|
305 |
|
306 // Load certificate |
|
307 if (!q_SSL_CTX_use_certificate(ctx, (X509 *)configuration.localCertificate.handle())) { |
|
308 q->setErrorString(QSslSocket::tr("Error loading local certificate, %1").arg(SSL_ERRORSTR())); |
|
309 emit q->error(QAbstractSocket::UnknownSocketError); |
|
310 return false; |
|
311 } |
|
312 |
|
313 // Load private key |
|
314 EVP_PKEY *pkey = q_EVP_PKEY_new(); |
|
315 if (configuration.privateKey.algorithm() == QSsl::Rsa) |
|
316 q_EVP_PKEY_assign_RSA(pkey, (RSA *)configuration.privateKey.handle()); |
|
317 else |
|
318 q_EVP_PKEY_assign_DSA(pkey, (DSA *)configuration.privateKey.handle()); |
|
319 if (!q_SSL_CTX_use_PrivateKey(ctx, pkey)) { |
|
320 q->setErrorString(QSslSocket::tr("Error loading private key, %1").arg(SSL_ERRORSTR())); |
|
321 emit q->error(QAbstractSocket::UnknownSocketError); |
|
322 return false; |
|
323 } |
|
324 |
|
325 // Check if the certificate matches the private key. |
|
326 if (!q_SSL_CTX_check_private_key(ctx)) { |
|
327 q->setErrorString(QSslSocket::tr("Private key does not certify public key, %1").arg(SSL_ERRORSTR())); |
|
328 emit q->error(QAbstractSocket::UnknownSocketError); |
|
329 return false; |
|
330 } |
|
331 } |
|
332 |
|
333 // Initialize peer verification. |
|
334 if (configuration.peerVerifyMode == QSslSocket::VerifyNone) { |
|
335 q_SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0); |
|
336 } else { |
|
337 q_SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, q_X509Callback); |
|
338 } |
|
339 |
|
340 // Set verification depth. |
|
341 if (configuration.peerVerifyDepth != 0) |
|
342 q_SSL_CTX_set_verify_depth(ctx, configuration.peerVerifyDepth); |
|
343 |
|
344 // Create and initialize SSL session |
|
345 if (!(ssl = q_SSL_new(ctx))) { |
|
346 // ### Bad error code |
|
347 q->setErrorString(QSslSocket::tr("Error creating SSL session, %1").arg(SSL_ERRORSTR())); |
|
348 q->setSocketError(QAbstractSocket::UnknownSocketError); |
|
349 emit q->error(QAbstractSocket::UnknownSocketError); |
|
350 return false; |
|
351 } |
|
352 |
|
353 // Clear the session. |
|
354 q_SSL_clear(ssl); |
|
355 errorList.clear(); |
|
356 |
|
357 // Initialize memory BIOs for encryption and decryption. |
|
358 readBio = q_BIO_new(q_BIO_s_mem()); |
|
359 writeBio = q_BIO_new(q_BIO_s_mem()); |
|
360 if (!readBio || !writeBio) { |
|
361 // ### Bad error code |
|
362 q->setErrorString(QSslSocket::tr("Error creating SSL session: %1").arg(SSL_ERRORSTR())); |
|
363 q->setSocketError(QAbstractSocket::UnknownSocketError); |
|
364 emit q->error(QAbstractSocket::UnknownSocketError); |
|
365 return false; |
|
366 } |
|
367 |
|
368 // Assign the bios. |
|
369 q_SSL_set_bio(ssl, readBio, writeBio); |
|
370 |
|
371 if (mode == QSslSocket::SslClientMode) |
|
372 q_SSL_set_connect_state(ssl); |
|
373 else |
|
374 q_SSL_set_accept_state(ssl); |
|
375 |
|
376 return true; |
|
377 } |
|
378 |
|
379 /*! |
|
380 \internal |
|
381 */ |
|
382 void QSslSocketPrivate::deinitialize() |
|
383 { |
|
384 q_CRYPTO_set_id_callback(0); |
|
385 q_CRYPTO_set_locking_callback(0); |
|
386 } |
|
387 |
|
388 /*! |
|
389 \internal |
|
390 |
|
391 Declared static in QSslSocketPrivate, makes sure the SSL libraries have |
|
392 been initialized. |
|
393 */ |
|
394 bool QSslSocketPrivate::ensureInitialized() |
|
395 { |
|
396 if (!q_resolveOpenSslSymbols()) |
|
397 return false; |
|
398 |
|
399 // Check if the library itself needs to be initialized. |
|
400 QMutexLocker locker(openssl_locks()->initLock()); |
|
401 static int q_initialized = false; |
|
402 if (!q_initialized) { |
|
403 q_initialized = true; |
|
404 |
|
405 // Initialize resources |
|
406 initNetworkResources(); |
|
407 |
|
408 // Initialize OpenSSL. |
|
409 q_CRYPTO_set_id_callback(id_function); |
|
410 q_CRYPTO_set_locking_callback(locking_function); |
|
411 if (q_SSL_library_init() != 1) |
|
412 return false; |
|
413 q_SSL_load_error_strings(); |
|
414 q_OpenSSL_add_all_algorithms(); |
|
415 |
|
416 // Initialize OpenSSL's random seed. |
|
417 if (!q_RAND_status()) { |
|
418 struct { |
|
419 int msec; |
|
420 int sec; |
|
421 void *stack; |
|
422 } randomish; |
|
423 |
|
424 int attempts = 500; |
|
425 do { |
|
426 if (attempts < 500) { |
|
427 #ifdef Q_OS_UNIX |
|
428 struct timespec ts = {0, 33333333}; |
|
429 nanosleep(&ts, 0); |
|
430 #else |
|
431 Sleep(3); |
|
432 #endif |
|
433 randomish.msec = attempts; |
|
434 } |
|
435 randomish.stack = (void *)&randomish; |
|
436 randomish.msec = QTime::currentTime().msec(); |
|
437 randomish.sec = QTime::currentTime().second(); |
|
438 q_RAND_seed((const char *)&randomish, sizeof(randomish)); |
|
439 } while (!q_RAND_status() && --attempts); |
|
440 if (!attempts) |
|
441 return false; |
|
442 } |
|
443 |
|
444 resetDefaultCiphers(); |
|
445 setDefaultCaCertificates(systemCaCertificates()); |
|
446 } |
|
447 return true; |
|
448 } |
|
449 |
|
450 /*! |
|
451 \internal |
|
452 |
|
453 Declared static in QSslSocketPrivate, backend-dependent loading of |
|
454 application-wide global ciphers. |
|
455 */ |
|
456 void QSslSocketPrivate::resetDefaultCiphers() |
|
457 { |
|
458 SSL_CTX *myCtx = q_SSL_CTX_new(q_SSLv23_client_method()); |
|
459 SSL *mySsl = q_SSL_new(myCtx); |
|
460 |
|
461 QList<QSslCipher> ciphers; |
|
462 |
|
463 STACK_OF(SSL_CIPHER) *supportedCiphers = q_SSL_get_ciphers(mySsl); |
|
464 for (int i = 0; i < q_sk_SSL_CIPHER_num(supportedCiphers); ++i) { |
|
465 if (SSL_CIPHER *cipher = q_sk_SSL_CIPHER_value(supportedCiphers, i)) { |
|
466 if (cipher->valid) { |
|
467 QSslCipher ciph = QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(cipher); |
|
468 if (!ciph.isNull()) { |
|
469 if (!ciph.name().toLower().startsWith(QLatin1String("adh"))) |
|
470 ciphers << ciph; |
|
471 } |
|
472 } |
|
473 } |
|
474 } |
|
475 |
|
476 q_SSL_CTX_free(myCtx); |
|
477 q_SSL_free(mySsl); |
|
478 |
|
479 setDefaultSupportedCiphers(ciphers); |
|
480 setDefaultCiphers(ciphers); |
|
481 } |
|
482 |
|
483 QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() |
|
484 { |
|
485 // Qt provides a default bundle of certificates |
|
486 QFile caBundle(QLatin1String(":/trolltech/network/ssl/qt-ca-bundle.crt")); |
|
487 if (caBundle.open(QIODevice::ReadOnly | QIODevice::Text)) |
|
488 return QSslCertificate::fromDevice(&caBundle); |
|
489 |
|
490 // Unreachable; return no bundle. |
|
491 return QList<QSslCertificate>(); |
|
492 } |
|
493 |
|
494 void QSslSocketBackendPrivate::startClientEncryption() |
|
495 { |
|
496 if (!initSslContext()) { |
|
497 // ### report error: internal OpenSSL failure |
|
498 return; |
|
499 } |
|
500 |
|
501 // Start connecting. This will place outgoing data in the BIO, so we |
|
502 // follow up with calling transmit(). |
|
503 startHandshake(); |
|
504 transmit(); |
|
505 } |
|
506 |
|
507 void QSslSocketBackendPrivate::startServerEncryption() |
|
508 { |
|
509 if (!initSslContext()) { |
|
510 // ### report error: internal OpenSSL failure |
|
511 return; |
|
512 } |
|
513 |
|
514 // Start connecting. This will place outgoing data in the BIO, so we |
|
515 // follow up with calling transmit(). |
|
516 startHandshake(); |
|
517 transmit(); |
|
518 } |
|
519 |
|
520 /*! |
|
521 \internal |
|
522 |
|
523 Transmits encrypted data between the BIOs and the socket. |
|
524 */ |
|
525 void QSslSocketBackendPrivate::transmit() |
|
526 { |
|
527 Q_Q(QSslSocket); |
|
528 |
|
529 // If we don't have any SSL context, don't bother transmitting. |
|
530 if (!ssl) |
|
531 return; |
|
532 |
|
533 bool transmitting; |
|
534 do { |
|
535 transmitting = false; |
|
536 |
|
537 // If the connection is secure, we can transfer data from the write |
|
538 // buffer (in plain text) to the write BIO through SSL_write. |
|
539 if (connectionEncrypted && !writeBuffer.isEmpty()) { |
|
540 qint64 totalBytesWritten = 0; |
|
541 int nextDataBlockSize; |
|
542 while ((nextDataBlockSize = writeBuffer.nextDataBlockSize()) > 0) { |
|
543 int writtenBytes = q_SSL_write(ssl, writeBuffer.readPointer(), nextDataBlockSize); |
|
544 if (writtenBytes <= 0) { |
|
545 // ### Better error handling. |
|
546 q->setErrorString(QSslSocket::tr("Unable to write data: %1").arg(SSL_ERRORSTR())); |
|
547 q->setSocketError(QAbstractSocket::UnknownSocketError); |
|
548 emit q->error(QAbstractSocket::UnknownSocketError); |
|
549 return; |
|
550 } |
|
551 #ifdef QSSLSOCKET_DEBUG |
|
552 qDebug() << "QSslSocketBackendPrivate::transmit: encrypted" << writtenBytes << "bytes"; |
|
553 #endif |
|
554 writeBuffer.free(writtenBytes); |
|
555 totalBytesWritten += writtenBytes; |
|
556 |
|
557 if (writtenBytes < nextDataBlockSize) { |
|
558 // break out of the writing loop and try again after we had read |
|
559 transmitting = true; |
|
560 break; |
|
561 } |
|
562 } |
|
563 |
|
564 if (totalBytesWritten > 0) { |
|
565 // Don't emit bytesWritten() recursively. |
|
566 if (!emittedBytesWritten) { |
|
567 emittedBytesWritten = true; |
|
568 emit q->bytesWritten(totalBytesWritten); |
|
569 emittedBytesWritten = false; |
|
570 } |
|
571 } |
|
572 } |
|
573 |
|
574 // Check if we've got any data to be written to the socket. |
|
575 QVarLengthArray<char, 4096> data; |
|
576 int pendingBytes; |
|
577 while (plainSocket->isValid() && (pendingBytes = q_BIO_pending(writeBio)) > 0) { |
|
578 // Read encrypted data from the write BIO into a buffer. |
|
579 data.resize(pendingBytes); |
|
580 int encryptedBytesRead = q_BIO_read(writeBio, data.data(), pendingBytes); |
|
581 |
|
582 // Write encrypted data from the buffer to the socket. |
|
583 plainSocket->write(data.constData(), encryptedBytesRead); |
|
584 #ifdef QSSLSOCKET_DEBUG |
|
585 qDebug() << "QSslSocketBackendPrivate::transmit: wrote" << encryptedBytesRead << "encrypted bytes to the socket"; |
|
586 #endif |
|
587 transmitting = true; |
|
588 } |
|
589 |
|
590 // Check if we've got any data to be read from the socket. |
|
591 if (!connectionEncrypted || !readBufferMaxSize || readBuffer.size() < readBufferMaxSize) |
|
592 while ((pendingBytes = plainSocket->bytesAvailable()) > 0) { |
|
593 // Read encrypted data from the socket into a buffer. |
|
594 data.resize(pendingBytes); |
|
595 // just peek() here because q_BIO_write could write less data than expected |
|
596 int encryptedBytesRead = plainSocket->peek(data.data(), pendingBytes); |
|
597 #ifdef QSSLSOCKET_DEBUG |
|
598 qDebug() << "QSslSocketBackendPrivate::transmit: read" << encryptedBytesRead << "encrypted bytes from the socket"; |
|
599 #endif |
|
600 // Write encrypted data from the buffer into the read BIO. |
|
601 int writtenToBio = q_BIO_write(readBio, data.constData(), encryptedBytesRead); |
|
602 |
|
603 // do the actual read() here and throw away the results. |
|
604 if (writtenToBio > 0) { |
|
605 // ### TODO: make this cheaper by not making it memcpy. E.g. make it work with data=0x0 or make it work with seek |
|
606 plainSocket->read(data.data(), writtenToBio); |
|
607 } else { |
|
608 // ### Better error handling. |
|
609 q->setErrorString(QSslSocket::tr("Unable to decrypt data: %1").arg(SSL_ERRORSTR())); |
|
610 q->setSocketError(QAbstractSocket::UnknownSocketError); |
|
611 emit q->error(QAbstractSocket::UnknownSocketError); |
|
612 return; |
|
613 } |
|
614 |
|
615 transmitting = true; |
|
616 } |
|
617 |
|
618 // If the connection isn't secured yet, this is the time to retry the |
|
619 // connect / accept. |
|
620 if (!connectionEncrypted) { |
|
621 #ifdef QSSLSOCKET_DEBUG |
|
622 qDebug() << "QSslSocketBackendPrivate::transmit: testing encryption"; |
|
623 #endif |
|
624 if (startHandshake()) { |
|
625 #ifdef QSSLSOCKET_DEBUG |
|
626 qDebug() << "QSslSocketBackendPrivate::transmit: encryption established"; |
|
627 #endif |
|
628 connectionEncrypted = true; |
|
629 transmitting = true; |
|
630 } else if (plainSocket->state() != QAbstractSocket::ConnectedState) { |
|
631 #ifdef QSSLSOCKET_DEBUG |
|
632 qDebug() << "QSslSocketBackendPrivate::transmit: connection lost"; |
|
633 #endif |
|
634 break; |
|
635 } else { |
|
636 #ifdef QSSLSOCKET_DEBUG |
|
637 qDebug() << "QSslSocketBackendPrivate::transmit: encryption not done yet"; |
|
638 #endif |
|
639 } |
|
640 } |
|
641 |
|
642 // If the request is small and the remote host closes the transmission |
|
643 // after sending, there's a chance that startHandshake() will already |
|
644 // have triggered a shutdown. |
|
645 if (!ssl) |
|
646 continue; |
|
647 |
|
648 // We always read everything from the SSL decryption buffers, even if |
|
649 // we have a readBufferMaxSize. There's no point in leaving data there |
|
650 // just so that readBuffer.size() == readBufferMaxSize. |
|
651 int readBytes = 0; |
|
652 data.resize(4096); |
|
653 ::memset(data.data(), 0, data.size()); |
|
654 do { |
|
655 // Don't use SSL_pending(). It's very unreliable. |
|
656 if ((readBytes = q_SSL_read(ssl, data.data(), data.size())) > 0) { |
|
657 #ifdef QSSLSOCKET_DEBUG |
|
658 qDebug() << "QSslSocketBackendPrivate::transmit: decrypted" << readBytes << "bytes"; |
|
659 #endif |
|
660 char *ptr = readBuffer.reserve(readBytes); |
|
661 ::memcpy(ptr, data.data(), readBytes); |
|
662 |
|
663 if (readyReadEmittedPointer) |
|
664 *readyReadEmittedPointer = true; |
|
665 emit q->readyRead(); |
|
666 transmitting = true; |
|
667 continue; |
|
668 } |
|
669 |
|
670 // Error. |
|
671 switch (q_SSL_get_error(ssl, readBytes)) { |
|
672 case SSL_ERROR_WANT_READ: |
|
673 case SSL_ERROR_WANT_WRITE: |
|
674 // Out of data. |
|
675 break; |
|
676 case SSL_ERROR_ZERO_RETURN: |
|
677 // The remote host closed the connection. |
|
678 #ifdef QSSLSOCKET_DEBUG |
|
679 qDebug() << "QSslSocketBackendPrivate::transmit: remote disconnect"; |
|
680 #endif |
|
681 plainSocket->disconnectFromHost(); |
|
682 break; |
|
683 default: |
|
684 // ### Handle errors better. |
|
685 q->setErrorString(QSslSocket::tr("Error while reading: %1").arg(SSL_ERRORSTR())); |
|
686 q->setSocketError(QAbstractSocket::UnknownSocketError); |
|
687 emit q->error(QAbstractSocket::UnknownSocketError); |
|
688 break; |
|
689 } |
|
690 } while (ssl && readBytes > 0); |
|
691 } while (ssl && ctx && transmitting); |
|
692 } |
|
693 |
|
694 static QSslError _q_OpenSSL_to_QSslError(int errorCode, const QSslCertificate &cert) |
|
695 { |
|
696 QSslError error; |
|
697 switch (errorCode) { |
|
698 case X509_V_OK: |
|
699 // X509_V_OK is also reported if the peer had no certificate. |
|
700 break; |
|
701 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: |
|
702 error = QSslError(QSslError::UnableToGetIssuerCertificate, cert); break; |
|
703 case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: |
|
704 error = QSslError(QSslError::UnableToDecryptCertificateSignature, cert); break; |
|
705 case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: |
|
706 error = QSslError(QSslError::UnableToDecodeIssuerPublicKey, cert); break; |
|
707 case X509_V_ERR_CERT_SIGNATURE_FAILURE: |
|
708 error = QSslError(QSslError::CertificateSignatureFailed, cert); break; |
|
709 case X509_V_ERR_CERT_NOT_YET_VALID: |
|
710 error = QSslError(QSslError::CertificateNotYetValid, cert); break; |
|
711 case X509_V_ERR_CERT_HAS_EXPIRED: |
|
712 error = QSslError(QSslError::CertificateExpired, cert); break; |
|
713 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: |
|
714 error = QSslError(QSslError::InvalidNotBeforeField, cert); break; |
|
715 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: |
|
716 error = QSslError(QSslError::InvalidNotAfterField, cert); break; |
|
717 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: |
|
718 error = QSslError(QSslError::SelfSignedCertificate, cert); break; |
|
719 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: |
|
720 error = QSslError(QSslError::SelfSignedCertificateInChain, cert); break; |
|
721 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: |
|
722 error = QSslError(QSslError::UnableToGetLocalIssuerCertificate, cert); break; |
|
723 case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: |
|
724 error = QSslError(QSslError::UnableToVerifyFirstCertificate, cert); break; |
|
725 case X509_V_ERR_CERT_REVOKED: |
|
726 error = QSslError(QSslError::CertificateRevoked, cert); break; |
|
727 case X509_V_ERR_INVALID_CA: |
|
728 error = QSslError(QSslError::InvalidCaCertificate, cert); break; |
|
729 case X509_V_ERR_PATH_LENGTH_EXCEEDED: |
|
730 error = QSslError(QSslError::PathLengthExceeded, cert); break; |
|
731 case X509_V_ERR_INVALID_PURPOSE: |
|
732 error = QSslError(QSslError::InvalidPurpose, cert); break; |
|
733 case X509_V_ERR_CERT_UNTRUSTED: |
|
734 error = QSslError(QSslError::CertificateUntrusted, cert); break; |
|
735 case X509_V_ERR_CERT_REJECTED: |
|
736 error = QSslError(QSslError::CertificateRejected, cert); break; |
|
737 default: |
|
738 error = QSslError(QSslError::UnspecifiedError, cert); break; |
|
739 } |
|
740 return error; |
|
741 } |
|
742 |
|
743 bool QSslSocketBackendPrivate::startHandshake() |
|
744 { |
|
745 Q_Q(QSslSocket); |
|
746 |
|
747 // Check if the connection has been established. Get all errors from the |
|
748 // verification stage. |
|
749 _q_sslErrorList()->mutex.lock(); |
|
750 _q_sslErrorList()->errors.clear(); |
|
751 int result = (mode == QSslSocket::SslClientMode) ? q_SSL_connect(ssl) : q_SSL_accept(ssl); |
|
752 |
|
753 const QList<QPair<int, int> > &lastErrors = _q_sslErrorList()->errors; |
|
754 for (int i = 0; i < lastErrors.size(); ++i) { |
|
755 const QPair<int, int> ¤tError = lastErrors.at(i); |
|
756 // Initialize the peer certificate chain in order to find which certificate caused this error |
|
757 if (configuration.peerCertificateChain.isEmpty()) |
|
758 configuration.peerCertificateChain = STACKOFX509_to_QSslCertificates(q_SSL_get_peer_cert_chain(ssl)); |
|
759 emit q->peerVerifyError(_q_OpenSSL_to_QSslError(currentError.first, |
|
760 configuration.peerCertificateChain.value(currentError.second))); |
|
761 if (q->state() != QAbstractSocket::ConnectedState) |
|
762 break; |
|
763 } |
|
764 |
|
765 errorList << lastErrors; |
|
766 _q_sslErrorList()->mutex.unlock(); |
|
767 |
|
768 // Connection aborted during handshake phase. |
|
769 if (q->state() != QAbstractSocket::ConnectedState) |
|
770 return false; |
|
771 |
|
772 // Check if we're encrypted or not. |
|
773 if (result <= 0) { |
|
774 switch (q_SSL_get_error(ssl, result)) { |
|
775 case SSL_ERROR_WANT_READ: |
|
776 case SSL_ERROR_WANT_WRITE: |
|
777 // The handshake is not yet complete. |
|
778 break; |
|
779 default: |
|
780 // ### Handle errors better |
|
781 q->setErrorString(QSslSocket::tr("Error during SSL handshake: %1").arg(SSL_ERRORSTR())); |
|
782 q->setSocketError(QAbstractSocket::SslHandshakeFailedError); |
|
783 #ifdef QSSLSOCKET_DEBUG |
|
784 qDebug() << "QSslSocketBackendPrivate::startHandshake: error!" << q->errorString(); |
|
785 #endif |
|
786 emit q->error(QAbstractSocket::SslHandshakeFailedError); |
|
787 q->abort(); |
|
788 } |
|
789 return false; |
|
790 } |
|
791 |
|
792 // Store the peer certificate and chain. For clients, the peer certificate |
|
793 // chain includes the peer certificate; for servers, it doesn't. Both the |
|
794 // peer certificate and the chain may be empty if the peer didn't present |
|
795 // any certificate. |
|
796 if (configuration.peerCertificateChain.isEmpty()) |
|
797 configuration.peerCertificateChain = STACKOFX509_to_QSslCertificates(q_SSL_get_peer_cert_chain(ssl)); |
|
798 X509 *x509 = q_SSL_get_peer_certificate(ssl); |
|
799 configuration.peerCertificate = QSslCertificatePrivate::QSslCertificate_from_X509(x509); |
|
800 q_X509_free(x509); |
|
801 |
|
802 // Start translating errors. |
|
803 QList<QSslError> errors; |
|
804 bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer |
|
805 || (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer |
|
806 && mode == QSslSocket::SslClientMode); |
|
807 |
|
808 // Check the peer certificate itself. First try the subject's common name |
|
809 // (CN) as a wildcard, then try all alternate subject name DNS entries the |
|
810 // same way. |
|
811 if (!configuration.peerCertificate.isNull()) { |
|
812 // but only if we're a client connecting to a server |
|
813 // if we're the server, don't check CN |
|
814 if (mode == QSslSocket::SslClientMode) { |
|
815 QString peerName = (verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName); |
|
816 QString commonName = configuration.peerCertificate.subjectInfo(QSslCertificate::CommonName); |
|
817 |
|
818 QRegExp regexp(commonName, Qt::CaseInsensitive, QRegExp::Wildcard); |
|
819 if (!regexp.exactMatch(peerName)) { |
|
820 bool matched = false; |
|
821 foreach (const QString &altName, configuration.peerCertificate |
|
822 .alternateSubjectNames().values(QSsl::DnsEntry)) { |
|
823 regexp.setPattern(altName); |
|
824 if (regexp.exactMatch(peerName)) { |
|
825 matched = true; |
|
826 break; |
|
827 } |
|
828 } |
|
829 if (!matched) { |
|
830 // No matches in common names or alternate names. |
|
831 QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate); |
|
832 errors << error; |
|
833 emit q->peerVerifyError(error); |
|
834 if (q->state() != QAbstractSocket::ConnectedState) |
|
835 return false; |
|
836 } |
|
837 } |
|
838 } |
|
839 } else { |
|
840 // No peer certificate presented. Report as error if the socket |
|
841 // expected one. |
|
842 if (doVerifyPeer) { |
|
843 QSslError error(QSslError::NoPeerCertificate); |
|
844 errors << error; |
|
845 emit q->peerVerifyError(error); |
|
846 if (q->state() != QAbstractSocket::ConnectedState) |
|
847 return false; |
|
848 } |
|
849 } |
|
850 |
|
851 // Translate errors from the error list into QSslErrors. |
|
852 for (int i = 0; i < errorList.size(); ++i) { |
|
853 const QPair<int, int> &errorAndDepth = errorList.at(i); |
|
854 int err = errorAndDepth.first; |
|
855 int depth = errorAndDepth.second; |
|
856 errors << _q_OpenSSL_to_QSslError(err, configuration.peerCertificateChain.value(depth)); |
|
857 } |
|
858 |
|
859 if (!errors.isEmpty()) { |
|
860 sslErrors = errors; |
|
861 emit q->sslErrors(errors); |
|
862 |
|
863 bool doEmitSslError; |
|
864 if (!ignoreErrorsList.empty()) { |
|
865 // check whether the errors we got are all in the list of expected errors |
|
866 // (applies only if the method QSslSocket::ignoreSslErrors(const QList<QSslError> &errors) |
|
867 // was called) |
|
868 doEmitSslError = false; |
|
869 for (int a = 0; a < errors.count(); a++) { |
|
870 if (!ignoreErrorsList.contains(errors.at(a))) { |
|
871 doEmitSslError = true; |
|
872 break; |
|
873 } |
|
874 } |
|
875 } else { |
|
876 // if QSslSocket::ignoreSslErrors(const QList<QSslError> &errors) was not called and |
|
877 // we get an SSL error, emit a signal unless we ignored all errors (by calling |
|
878 // QSslSocket::ignoreSslErrors() ) |
|
879 doEmitSslError = !ignoreAllSslErrors; |
|
880 } |
|
881 // check whether we need to emit an SSL handshake error |
|
882 if (doVerifyPeer && doEmitSslError) { |
|
883 q->setErrorString(sslErrors.first().errorString()); |
|
884 q->setSocketError(QAbstractSocket::SslHandshakeFailedError); |
|
885 emit q->error(QAbstractSocket::SslHandshakeFailedError); |
|
886 plainSocket->disconnectFromHost(); |
|
887 return false; |
|
888 } |
|
889 } else { |
|
890 sslErrors.clear(); |
|
891 } |
|
892 |
|
893 // if we have a max read buffer size, reset the plain socket's to 1k |
|
894 if (readBufferMaxSize) |
|
895 plainSocket->setReadBufferSize(1024); |
|
896 |
|
897 connectionEncrypted = true; |
|
898 emit q->encrypted(); |
|
899 if (autoStartHandshake && pendingClose) { |
|
900 pendingClose = false; |
|
901 q->disconnectFromHost(); |
|
902 } |
|
903 return true; |
|
904 } |
|
905 |
|
906 void QSslSocketBackendPrivate::disconnectFromHost() |
|
907 { |
|
908 if (ssl) { |
|
909 q_SSL_shutdown(ssl); |
|
910 transmit(); |
|
911 } |
|
912 plainSocket->disconnectFromHost(); |
|
913 } |
|
914 |
|
915 void QSslSocketBackendPrivate::disconnected() |
|
916 { |
|
917 if (ssl) { |
|
918 q_SSL_free(ssl); |
|
919 ssl = 0; |
|
920 } |
|
921 if (ctx) { |
|
922 q_SSL_CTX_free(ctx); |
|
923 ctx = 0; |
|
924 } |
|
925 } |
|
926 |
|
927 QSslCipher QSslSocketBackendPrivate::sessionCipher() const |
|
928 { |
|
929 if (!ssl || !ctx) |
|
930 return QSslCipher(); |
|
931 #if OPENSSL_VERSION_NUMBER >= 0x10000000L |
|
932 // FIXME This is fairly evil, but needed to keep source level compatibility |
|
933 // with the OpenSSL 0.9.x implementation at maximum -- some other functions |
|
934 // don't take a const SSL_CIPHER* when they should |
|
935 SSL_CIPHER *sessionCipher = const_cast<SSL_CIPHER *>(q_SSL_get_current_cipher(ssl)); |
|
936 #else |
|
937 SSL_CIPHER *sessionCipher = q_SSL_get_current_cipher(ssl); |
|
938 #endif |
|
939 return sessionCipher ? QSslCipher_from_SSL_CIPHER(sessionCipher) : QSslCipher(); |
|
940 } |
|
941 |
|
942 QList<QSslCertificate> QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509) |
|
943 { |
|
944 ensureInitialized(); |
|
945 QList<QSslCertificate> certificates; |
|
946 for (int i = 0; i < q_sk_X509_num(x509); ++i) { |
|
947 if (X509 *entry = q_sk_X509_value(x509, i)) |
|
948 certificates << QSslCertificatePrivate::QSslCertificate_from_X509(entry); |
|
949 } |
|
950 return certificates; |
|
951 } |
|
952 |
|
953 QT_END_NAMESPACE |