source: trunk/src/network/ssl/qsslsocket_openssl.cpp@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 34.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtNetwork module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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
61static void initNetworkResources()
62{
63 // Initialize resources
64 Q_INIT_RESOURCE(network);
65}
66
67QT_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*/
89class QOpenSslLocks
90{
91public:
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
129private:
130 QMutex initLocker;
131 QMutex locksLocker;
132 QMutex **locks;
133};
134Q_GLOBAL_STATIC(QOpenSslLocks, openssl_locks)
135
136extern "C" {
137static 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}
147static unsigned long id_function()
148{
149 return (unsigned long)QThread::currentThreadId();
150}
151} // extern "C"
152
153QSslSocketBackendPrivate::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
164QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
165{
166}
167
168QSslCipher 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.
208struct QSslErrorList
209{
210 QMutex mutex;
211 QList<QPair<int, int> > errors;
212};
213Q_GLOBAL_STATIC(QSslErrorList, _q_sslErrorList)
214static 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
226bool 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;
234init_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*/
382void 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*/
394bool 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*/
456void 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
483QList<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
494void 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
507void 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*/
525void 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
694static 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
743bool 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> &currentError = 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 (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
906void QSslSocketBackendPrivate::disconnectFromHost()
907{
908 if (ssl) {
909 q_SSL_shutdown(ssl);
910 transmit();
911 }
912 plainSocket->disconnectFromHost();
913}
914
915void 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
927QSslCipher 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
942QList<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
953QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.