40 #include <QtCore/QDataStream>
41 #include <QtCore/QTime>
42 #include <QtNetwork/QTcpSocket>
43 #include <QtNetwork/QHostInfo>
44 #include <QtNetwork/QSslConfiguration>
45 #include <QtDBus/QtDBus>
55 Q_DECLARE_OPERATORS_FOR_FLAGS(TCPSlaveBase::SslResult)
91 class TCPSlaveBase::TcpSlaveBasePrivate
98 sslMetaData.insert(
"ssl_in_use",
"TRUE");
100 sslMetaData.insert(
"ssl_protocol_version",
socket.negotiatedSslVersionName());
105 sslMetaData.insert(
"ssl_cipher", sslCipher);
106 sslMetaData.insert(
"ssl_cipher_name", cipher.
name());
109 sslMetaData.insert(
"ssl_peer_ip",
ip);
113 for (
int i = 0; i < sslErrors.count(); i++) {
114 if (sslErrors[i].certificate().isNull()) {
116 socket.peerCertificateChain()[0]);
122 Q_FOREACH (
const QSslCertificate &cert,
socket.peerCertificateChain()) {
128 if (errorStr.endsWith(
'\t')) {
134 sslMetaData.insert(
"ssl_cert_errors", errorStr);
137 Q_FOREACH (
const QSslCertificate &cert,
socket.peerCertificateChain()) {
138 peerCertChain.append(cert.toPem());
139 peerCertChain.append(
'\x01');
141 peerCertChain.chop(1);
142 sslMetaData.insert(
"ssl_peer_chain", peerCertChain);
146 void clearSslMetaData()
149 sslMetaData.insert(
"ssl_in_use",
"FALSE");
153 void sendSslMetaData()
155 MetaData::ConstIterator it = sslMetaData.constBegin();
156 for (; it != sslMetaData.constEnd(); ++it) {
157 q->setMetaData(it.key(), it.value());
162 const QSslConfiguration& configuration = QSslConfiguration(),
163 int waitForEncryptedTimeout = -1);
174 QByteArray serviceName;
195 const QByteArray &poolSocket,
196 const QByteArray &appSocket,
198 :
SlaveBase(protocol, poolSocket, appSocket),
199 d(new TcpSlaveBasePrivate(this))
201 d->isBlocking =
true;
203 d->serviceName = protocol;
205 d->autoSSL = autoSSL;
210 d->socket.setReadBufferSize(14680064);
222 ssize_t
written = d->socket.write(data, len);
224 kDebug(7027) <<
"d->socket.write() returned -1! Socket error is"
225 << d->socket.error() <<
", Socket state is" << d->socket.state();
228 bool success =
false;
231 success = d->socket.waitForBytesWritten(-1);
236 success = d->socket.waitForBytesWritten(0);
242 kDebug(7027) <<
"Write failed, will return -1! Socket error is"
243 << d->socket.error() <<
", Socket state is" << d->socket.state()
244 <<
"Return value of waitForBytesWritten() is" << success;
255 d->clearSslMetaData();
256 kDebug(7029) <<
"lost SSL connection.";
260 if (!d->socket.bytesAvailable()) {
262 d->socket.waitForReadyRead(timeout);
268 QNetworkProxy::applicationProxy().type() == QNetworkProxy::NoProxy) {
271 d->socket.waitForReadyRead(0);
274 return d->socket.read(data, len);
281 d->clearSslMetaData();
282 kDebug(7029) <<
"lost SSL connection.";
287 ssize_t readTotal = 0;
289 if (!d->socket.bytesAvailable())
290 d->socket.waitForReadyRead(timeout);
291 ssize_t readStep = d->socket.readLine(&data[readTotal], len-readTotal);
295 readTotal += readStep;
296 }
while (readTotal == 0 || data[readTotal-1] !=
'\n');
311 error(errCode, errorString);
317 d->clearSslMetaData();
320 errorString->clear();
323 d->socket.setVerificationPeerName(host);
328 if (
metaData(
"main_frame_request") ==
"TRUE"
329 &&
metaData(
"ssl_activate_warnings") ==
"TRUE"
330 &&
metaData(
"ssl_was_in_use") ==
"TRUE"
335 "mode. Transmissions will no "
336 "longer be encrypted.\nThis "
337 "means that a third party could "
338 "observe your data in transit."),
340 i18n(
"Security Information"),
342 "WarnOnLeaveSSLMode");
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);
376 KTcpSocket::SslVersions alreadyTriedSslVersions = trySslVersion;
383 d->socket.connectToHost(host, port);
384 const bool connectOk = d->socket.waitForConnected(timeout > -1 ? timeout : -1);
386 kDebug(7027) <<
"Socket: state=" << d->socket.state()
387 <<
", error=" << d->socket.error()
388 <<
", connected?" << connectOk;
392 *errorString = host + QLatin1String(
": ") + d->socket.errorString();
393 switch (d->socket.error()) {
409 d->ip = d->socket.peerAddress().toString();
410 d->port = d->socket.peerPort();
413 SslResult res = d->startTLSInternal(trySslVersion, sslConfig, 30000 );
415 #if QT_VERSION >= 0x040800
416 if (!sslConfig.testSslOption(QSsl::SslOptionDisableCompression)) {
417 sslConfig.setSslOption(QSsl::SslOptionDisableCompression,
true);
424 alreadyTriedSslVersions |= trySslVersion;
425 #if QT_VERSION >= 0x040800
426 sslConfig.setSslOption(QSsl::SslOptionDisableCompression,
false);
433 alreadyTriedSslVersions |= trySslVersion;
434 #if QT_VERSION >= 0x040800
435 sslConfig.setSslOption(QSsl::SslOptionDisableCompression,
false);
442 alreadyTriedSslVersions |= trySslVersion;
443 #if QT_VERSION >= 0x040800
444 sslConfig.setSslOption(QSsl::SslOptionDisableCompression,
false);
451 if (res & ResultFailed) {
453 *errorString =
i18nc(
"%1 is a host name",
"%1: SSL negotiation failed", host);
460 setMetaData(QLatin1String(
"{internal~currenthost}LastUsedSslVersion"),
463 #if QT_VERSION >= 0x040800
464 if (sslConfig.testSslOption(QSsl::SslOptionDisableCompression) && !shouldSslCompressBeDisabled) {
465 setMetaData(QLatin1String(
"{internal~currenthost}LastUsedSslDisableCompressionFlag"),
497 d->socket.disconnectFromHost();
499 d->socket.waitForDisconnected(-1);
520 return d->socket.atEnd();
530 TCPSlaveBase::SslResult TCPSlaveBase::TcpSlaveBasePrivate::startTLSInternal (
KTcpSocket::SslVersion version,
531 const QSslConfiguration& sslConfig,
532 int waitForEncryptedTimeout)
534 q->selectClientCertificate();
539 #if QT_VERSION >= 0x040800
540 kDebug(7027) <<
"Trying SSL handshake with protocol:" << version
541 <<
", SSL compression ON:" << sslConfig.testSslOption(QSsl::SslOptionDisableCompression);
544 socket.setAdvertisedSslVersion(version);
547 if (!sslConfig.isNull())
548 socket.setSslConfiguration(sslConfig);
554 socket.ignoreSslErrors();
555 socket.startClientEncryption();
556 const bool encryptionStarted = socket.waitForEncrypted(waitForEncryptedTimeout);
562 || cipher.
isNull() || cipher.
usedBits() == 0 || socket.peerCertificateChain().isEmpty()) {
565 kDebug(7029) <<
"Initial SSL handshake failed. encryptionStarted is"
566 << encryptionStarted <<
", cipher.isNull() is" << cipher.
isNull()
567 <<
", cipher.usedBits() is" << cipher.
usedBits()
568 <<
", length of certificate chain is" << socket.peerCertificateChain().count()
569 <<
", the socket says:" << socket.errorString()
570 <<
"and the list of SSL errors contains"
571 << socket.sslErrors().count() <<
"items.";
572 Q_FOREACH(
const KSslError& sslError, socket.sslErrors()) {
575 return ResultFailed | ResultFailedEarly;
578 kDebug(7029) <<
"Cipher info - "
579 <<
" advertised SSL protocol version" << socket.advertisedSslVersion()
580 <<
" negotiated SSL protocol version" << socket.negotiatedSslVersion()
584 <<
" name:" << cipher.
name()
586 <<
" usedBits:" << cipher.
usedBits();
588 sslErrors = socket.sslErrors();
600 q->sendAndKeepMetaData();
602 SslResult rc = q->verifyServerCertificate();
603 if (rc & ResultFailed) {
606 kDebug(7029) <<
"server certificate verification failed.";
607 socket.disconnectFromHost();
609 }
else if (rc & ResultOverridden) {
610 kDebug(7029) <<
"server certificate verification failed but continuing at user's request.";
614 if (q->metaData(
"ssl_activate_warnings") ==
"TRUE"
615 && q->metaData(
"ssl_was_in_use") ==
"FALSE"
616 && sslSettings.warnOnEnter()) {
618 int msgResult = q->messageBox(
i18n(
"You are about to enter secure mode. "
619 "All transmissions will be encrypted "
620 "unless otherwise noted.\nThis means "
621 "that no third party will be able to "
622 "easily observe your data in transit."),
624 i18n(
"Security Information"),
625 i18n(
"Display SSL &Information"),
627 "WarnOnEnterSSLMode");
629 q->messageBox(SSLMessageBox , host);
636 void TCPSlaveBase::selectClientCertificate()
640 bool send =
false, prompt =
false,
save =
false, forcePrompt =
false;
645 if (
metaData(
"ssl_no_client_cert") ==
"TRUE")
return;
646 forcePrompt = (
metaData(
"ssl_force_cert_prompt") ==
"TRUE");
654 if (!d->kssl)
return;
661 send =
true; prompt =
false;
664 send =
false; prompt =
false;
668 send =
false; prompt =
true;
701 certname =
metaData(
"ssl_demand_certificate");
702 if (!certname.isEmpty()) {
709 if (certname.isEmpty() && !prompt && !forcePrompt)
return;
712 if (prompt || forcePrompt) {
715 QStringList::const_iterator it = certs.begin();
716 while (it != certs.end()) {
720 it = certs.erase(it);
727 if (certs.isEmpty())
return;
729 if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(
"org.kde.kio.uiserver")) {
734 QDBusInterface uis(
"org.kde.kio.uiserver",
"/UIServer",
"org.kde.KIO.UIServer");
736 QDBusMessage retVal = uis.call(
"showSSLCertDialog", d->host, certs,
metaData(
"window-id").toLongLong());
737 if (retVal.type() == QDBusMessage::ReplyMessage) {
738 if (retVal.arguments().at(0).toBool()) {
739 send = retVal.arguments().at(1).toBool();
740 save = retVal.arguments().at(2).toBool();
741 certname = retVal.arguments().at(3).toString();
762 ai.
prompt =
i18n(
"Enter the certificate password:");
765 ai.
url.setHost(certname);
776 i18n(
"Unable to open the certificate. Try a new password?")))
788 if (!d->kssl->setClientCertificate(pkcs)) {
790 "client certificate for the session "
791 "failed."),
i18n(
"SSL"));
795 kDebug(7029) <<
"Client SSL certificate is being used.";
807 TCPSlaveBase::SslResult TCPSlaveBase::verifyServerCertificate()
811 if (d->sslErrors.isEmpty()) {
813 }
else if (d->sslNoUi) {
818 if (!fatalErrors.isEmpty()) {
828 if (remainingErrors.isEmpty()) {
829 kDebug(7029) <<
"Error list empty after removing errors to be ignored. Continuing.";
835 QString message =
i18n(
"The server failed the authenticity check (%1).\n\n", d->host);
836 Q_FOREACH (
const KSslError &err, d->sslErrors) {
838 message.append(
'\n');
840 message = message.trimmed();
845 i18n(
"Server Authentication"),
846 i18n(
"&Details"),
i18n(
"Co&ntinue"));
859 i18n(
"Would you like to accept this "
860 "certificate forever without "
862 i18n(
"Server Authentication"),
864 i18n(
"&Current Session only"));
865 QDateTime ruleExpiry = QDateTime::currentDateTime();
868 ruleExpiry = ruleExpiry.addYears(1000);
871 ruleExpiry = ruleExpiry.addSecs(30*60);
882 #if 0 //### need to to do something like the old code about the main and subframe stuff
883 kDebug(7029) <<
"SSL HTTP frame the parent? " <<
metaData(
"main_frame_request");
889 KSSLCertificateCache::KSSLCertificatePolicy cp =
890 d->certCache->getPolicyByCertificate(pc);
898 if (cp == KSSLCertificateCache::Unknown ||
899 cp == KSSLCertificateCache::Ambiguous) {
900 cp = KSSLCertificateCache::Prompt;
903 permacache = d->certCache->isPermanent(pc);
906 if (!_IPmatchesCN && cp == KSSLCertificateCache::Accept) {
907 cp = KSSLCertificateCache::Prompt;
914 d->certCache->addCertificate(pc, cp, permacache);
915 if (doAddHost) d->certCache->addHost(pc, d->host);
918 KSSLCertificateCache::KSSLCertificatePolicy cp =
919 d->certCache->getPolicyByCertificate(pc);
924 bool certAndIPTheSame = (d->ip ==
metaData(
"ssl_parent_ip") &&
925 pc.toString() ==
metaData(
"ssl_parent_cert"));
928 if (certAndIPTheSame) {
957 if (cp == KSSLCertificateCache::Accept) {
958 if (certAndIPTheSame) {
963 i18n(
"You have indicated that you wish to accept this certificate, but it is not issued to the server who is presenting it. Do you wish to continue loading?"),
964 i18n(
"Server Authentication"));
968 d->certCache->addHost(pc, d->host);
974 }
else if (cp == KSSLCertificateCache::Reject) {
975 messageBox(
Information,
i18n(
"SSL certificate is being rejected as requested. You can disable this in the KDE System Settings."),
976 i18n(
"Server Authentication"));
998 if (d->socket.bytesAvailable()) {
1001 return d->socket.waitForReadyRead(t * 1000);
1007 kWarning(7029) <<
"Caller requested non-blocking mode, but that doesn't work";
1016 d->sendSslMetaData();