346
KTcpSocket::SslVersion trySslVersion = KTcpSocket::TlsV1;
347
const int timeout = readTimeout() * 1000;
353
By default the SSL handshake attempt uses these settings in the order shown:
355
1.) Protocol: KTcpSocket::SecureProtocols SSL compression: ON (DEFAULT)
356
2.) Protocol: KTcpSocket::SecureProtocols SSL compression: OFF
357
3.) Protocol: KTcpSocket::TlsV1 SSL compression: ON
358
4.) Protocol: KTcpSocket::TlsV1 SSL compression: OFF
359
5.) Protocol: KTcpSocket::SslV3 SSL compression: ON
360
6.) Protocol: KTcpSocket::SslV3 SSL compression: OFF
362
If any combination other than the one marked DEFAULT is used to complete
363
the SSL handshake, then that combination will be cached using KIO's internal
364
meta-data mechanism in order to speed up future connections to the same host.
367
QSslConfiguration sslConfig = d->socket.sslConfiguration();
368
#if QT_VERSION >= 0x040800
369
const bool isSslCompressionDisabled = sslConfig.testSslOption(QSsl::SslOptionDisableCompression);
370
const bool shouldSslCompressBeDisabled = config()->readEntry("LastUsedSslDisableCompressionFlag", isSslCompressionDisabled);
371
sslConfig.setSslOption(QSsl::SslOptionDisableCompression, shouldSslCompressBeDisabled);
374
const int lastSslVerson = config()->readEntry("LastUsedSslVersion", static_cast<int>(KTcpSocket::SecureProtocols));
375
KTcpSocket::SslVersion trySslVersion = static_cast<KTcpSocket::SslVersion>(lastSslVerson);
376
KTcpSocket::SslVersions alreadyTriedSslVersions = trySslVersion;
378
const int timeout = (connectTimeout() * 1000);
349
380
disconnectFromHost(); //Reset some state, even if we are already disconnected
352
383
d->socket.connectToHost(host, port);
353
384
const bool connectOk = d->socket.waitForConnected(timeout > -1 ? timeout : -1);
355
kDebug(7029) << ", Socket state:" << d->socket.state()
356
<< "Socket error:" << d->socket.error()
357
<< ", Connection succeeded:" << connectOk;
386
kDebug(7027) << "Socket: state=" << d->socket.state()
387
<< ", error=" << d->socket.error()
388
<< ", connected?" << connectOk;
359
390
if (d->socket.state() != KTcpSocket::ConnectedState) {
379
410
d->port = d->socket.peerPort();
381
412
if (d->autoSSL) {
382
SslResult res = startTLSInternal(trySslVersion);
383
if ((res & ResultFailed) && (res & ResultFailedEarly)
384
&& (trySslVersion == KTcpSocket::TlsV1)) {
385
trySslVersion = KTcpSocket::SslV3;
387
//### SSL 2.0 is (close to) dead and it's a good thing, too.
413
SslResult res = d->startTLSInternal(trySslVersion, sslConfig, 30000 /*30 secs timeout*/);
414
if ((res & ResultFailed) && (res & ResultFailedEarly)) {
415
#if QT_VERSION >= 0x040800
416
if (!sslConfig.testSslOption(QSsl::SslOptionDisableCompression)) {
417
sslConfig.setSslOption(QSsl::SslOptionDisableCompression, true);
422
if (!(alreadyTriedSslVersions & KTcpSocket::SecureProtocols)) {
423
trySslVersion = KTcpSocket::SecureProtocols;
424
alreadyTriedSslVersions |= trySslVersion;
425
#if QT_VERSION >= 0x040800
426
sslConfig.setSslOption(QSsl::SslOptionDisableCompression, false);
431
if (!(alreadyTriedSslVersions & KTcpSocket::TlsV1)) {
432
trySslVersion = KTcpSocket::TlsV1;
433
alreadyTriedSslVersions |= trySslVersion;
434
#if QT_VERSION >= 0x040800
435
sslConfig.setSslOption(QSsl::SslOptionDisableCompression, false);
440
if (!(alreadyTriedSslVersions & KTcpSocket::SslV3)) {
441
trySslVersion = KTcpSocket::SslV3;
442
alreadyTriedSslVersions |= trySslVersion;
443
#if QT_VERSION >= 0x040800
444
sslConfig.setSslOption(QSsl::SslOptionDisableCompression, false);
450
//### SSL 2.0 is (close to) dead and it's a good thing, too.
389
451
if (res & ResultFailed) {
391
453
*errorString = i18nc("%1 is a host name", "%1: SSL negotiation failed", host);
392
454
return ERR_COULD_NOT_CONNECT;
457
// If the SSL handshake was done with anything protocol other than the default,
458
// save that information so that any subsequent requests do not have to do thesame thing.
459
if (trySslVersion != KTcpSocket::SecureProtocols && lastSslVerson == KTcpSocket::SecureProtocols) {
460
setMetaData(QLatin1String("{internal~currenthost}LastUsedSslVersion"),
461
QString::number(trySslVersion));
463
#if QT_VERSION >= 0x040800
464
if (sslConfig.testSslOption(QSsl::SslOptionDisableCompression) && !shouldSslCompressBeDisabled) {
465
setMetaData(QLatin1String("{internal~currenthost}LastUsedSslDisableCompressionFlag"),
466
QString::number(true));
472
// Code flow never gets here but let's make the compiler happy.
473
// More: the stack allocation of QSslSettings seems to be confusing the compiler;
474
// in fact, any non-POD allocation does.
475
// even a 'return 0;' directly after the allocation (so before the while(true))
476
// is ignored. definitely seems to be a compiler bug? - aseigo
400
480
void TCPSlaveBase::disconnectFromHost()
494
TCPSlaveBase::SslResult TCPSlaveBase::startTLSInternal(uint v_)
574
TCPSlaveBase::SslResult TCPSlaveBase::TcpSlaveBasePrivate::startTLSInternal (KTcpSocket::SslVersion version,
575
const QSslConfiguration& sslConfig,
576
int waitForEncryptedTimeout)
496
KTcpSocket::SslVersion sslVersion = static_cast<KTcpSocket::SslVersion>(v_);
497
selectClientCertificate();
578
q->selectClientCertificate();
499
580
//setMetaData("ssl_session_id", d->kssl->session()->toString());
500
581
//### we don't support session reuse for now...
504
d->socket.setAdvertisedSslVersion(sslVersion);
583
#if QT_VERSION >= 0x040800
584
kDebug(7027) << "Trying SSL handshake with protocol:" << version
585
<< ", SSL compression ON:" << sslConfig.testSslOption(QSsl::SslOptionDisableCompression);
587
// Set the SSL version to use...
588
socket.setAdvertisedSslVersion(version);
590
// Set SSL configuration information
591
if (!sslConfig.isNull())
592
socket.setSslConfiguration(sslConfig);
506
594
/* Usually ignoreSslErrors() would be called in the slot invoked by the sslErrors()
507
595
signal but that would mess up the flow of control. We will check for errors
508
596
anyway to decide if we want to continue connecting. Otherwise ignoreSslErrors()
509
597
before connecting would be very insecure. */
510
d->socket.ignoreSslErrors();
511
d->socket.startClientEncryption();
512
const bool encryptionStarted = d->socket.waitForEncrypted(-1);
598
socket.ignoreSslErrors();
599
socket.startClientEncryption();
600
const bool encryptionStarted = socket.waitForEncrypted(waitForEncryptedTimeout);
514
602
//Set metadata, among other things for the "SSL Details" dialog
515
KSslCipher cipher = d->socket.sessionCipher();
603
KSslCipher cipher = socket.sessionCipher();
517
if (!encryptionStarted || d->socket.encryptionMode() != KTcpSocket::SslClientMode
518
|| cipher.isNull() || cipher.usedBits() == 0 || d->socket.peerCertificateChain().isEmpty()) {
520
d->clearSslMetaData();
605
if (!encryptionStarted || socket.encryptionMode() != KTcpSocket::SslClientMode
606
|| cipher.isNull() || cipher.usedBits() == 0 || socket.peerCertificateChain().isEmpty()) {
521
609
kDebug(7029) << "Initial SSL handshake failed. encryptionStarted is"
522
610
<< encryptionStarted << ", cipher.isNull() is" << cipher.isNull()
523
611
<< ", cipher.usedBits() is" << cipher.usedBits()
524
<< ", length of certificate chain is" << d->socket.peerCertificateChain().count()
525
<< ", the socket says:" << d->socket.errorString()
612
<< ", length of certificate chain is" << socket.peerCertificateChain().count()
613
<< ", the socket says:" << socket.errorString()
526
614
<< "and the list of SSL errors contains"
527
<< d->socket.sslErrors().count() << "items.";
615
<< socket.sslErrors().count() << "items.";
616
Q_FOREACH(const KSslError& sslError, socket.sslErrors()) {
617
kDebug(7029) << "SSL ERROR: (" << sslError.error() << ")" << sslError.errorString();
528
619
return ResultFailed | ResultFailedEarly;
531
622
kDebug(7029) << "Cipher info - "
532
<< " advertised SSL protocol version" << d->socket.advertisedSslVersion()
533
<< " negotiated SSL protocol version" << d->socket.negotiatedSslVersion()
623
<< " advertised SSL protocol version" << socket.advertisedSslVersion()
624
<< " negotiated SSL protocol version" << socket.negotiatedSslVersion()
534
625
<< " authenticationMethod:" << cipher.authenticationMethod()
535
626
<< " encryptionMethod:" << cipher.encryptionMethod()
536
627
<< " keyExchangeMethod:" << cipher.keyExchangeMethod()
541
632
// Since we connect by IP (cf. KIO::HostInfo) the SSL code will not recognize
542
633
// that the site certificate belongs to the domain. We therefore do the
543
634
// domain<->certificate matching here.
544
d->sslErrors = d->socket.sslErrors();
545
QSslCertificate peerCert = d->socket.peerCertificateChain().first();
546
QMutableListIterator<KSslError> it(d->sslErrors);
635
sslErrors = socket.sslErrors();
636
QSslCertificate peerCert = socket.peerCertificateChain().first();
637
QMutableListIterator<KSslError> it(sslErrors);
547
638
while (it.hasNext()) {
548
639
// As of 4.4.0 Qt does not assign a certificate to the QSslError it emits
549
640
// *in the case of HostNameMismatch*. A HostNameMismatch, however, will always
563
654
domainPatterns += peerCert.alternateSubjectNames().values(QSsl::DnsEntry);
564
655
bool names_match = false;
565
656
foreach (const QString &dp, domainPatterns) {
566
if (isMatchingHostname(dp, d->host)) {
657
if (isMatchingHostname(dp, host)) {
567
658
names_match = true;
571
662
if (!names_match) {
572
d->sslErrors.insert(0, KSslError(KSslError::HostNameMismatch, peerCert));
663
sslErrors.insert(0, KSslError(KSslError::HostNameMismatch, peerCert));
575
666
// TODO: review / rewrite / remove the comment
581
672
// from here, for example. And Konqi will be the second application to connect
583
674
// Therefore we choose to have our metadata and send it, too :)
585
sendAndKeepMetaData();
676
q->sendAndKeepMetaData();
587
SslResult rc = verifyServerCertificate();
678
SslResult rc = q->verifyServerCertificate();
588
679
if (rc & ResultFailed) {
590
d->clearSslMetaData();
591
682
kDebug(7029) << "server certificate verification failed.";
592
d->socket.disconnectFromHost(); //Make the connection fail (cf. ignoreSslErrors())
683
socket.disconnectFromHost(); //Make the connection fail (cf. ignoreSslErrors())
593
684
return ResultFailed;
594
685
} else if (rc & ResultOverridden) {
595
686
kDebug(7029) << "server certificate verification failed but continuing at user's request.";
598
689
//"warn" when starting SSL/TLS
599
if (metaData("ssl_activate_warnings") == "TRUE"
600
&& metaData("ssl_was_in_use") == "FALSE"
601
&& d->sslSettings.warnOnEnter()) {
690
if (q->metaData("ssl_activate_warnings") == "TRUE"
691
&& q->metaData("ssl_was_in_use") == "FALSE"
692
&& sslSettings.warnOnEnter()) {
603
int msgResult = messageBox(i18n("You are about to enter secure mode. "
694
int msgResult = q->messageBox(i18n("You are about to enter secure mode. "
604
695
"All transmissions will be encrypted "
605
696
"unless otherwise noted.\nThis means "
606
697
"that no third party will be able to "