Previously, MD5 was used. Like the core password hashing update,
this implements a versioning system so that the digest will be
automagically upgraded without bugging the user. If for some
reason the user downgrades again, the client will still work but
the user will be asked to validate the certificate again.
SHA2-256 is more common for storing certificate digests, but in
this case, SHA2-512 was used. This is because Qt4 does not
implement any hash higher than SHA1 and a SHA2-512 implementation
is already bundled for use with the core password hashing.
#include "clientsettings.h"
#include "peerfactory.h"
#include "clientsettings.h"
#include "peerfactory.h"
+#if QT_VERSION < 0x050000
+# include "../../3rdparty/sha512/sha512.h"
+#endif
+
using namespace Protocol;
ClientAuthHandler::ClientAuthHandler(CoreAccount account, QObject *parent)
using namespace Protocol;
ClientAuthHandler::ClientAuthHandler(CoreAccount account, QObject *parent)
}
s.setAccountValue("ShowNoCoreSslWarning", false);
s.setAccountValue("SslCert", QString());
}
s.setAccountValue("ShowNoCoreSslWarning", false);
s.setAccountValue("SslCert", QString());
+ s.setAccountValue("SslCertDigestVersion", QVariant(QVariant::Int));
}
if (_legacy)
onConnectionReady();
}
if (_legacy)
onConnectionReady();
// That way, a warning will appear in case it becomes invalid at some point
CoreAccountSettings s;
s.setAccountValue("SSLCert", QString());
// That way, a warning will appear in case it becomes invalid at some point
CoreAccountSettings s;
s.setAccountValue("SSLCert", QString());
+ s.setAccountValue("SslCertDigestVersion", QVariant(QVariant::Int));
CoreAccountSettings s;
QByteArray knownDigest = s.accountValue("SslCert").toByteArray();
CoreAccountSettings s;
QByteArray knownDigest = s.accountValue("SslCert").toByteArray();
+ ClientAuthHandler::DigestVersion knownDigestVersion = static_cast<ClientAuthHandler::DigestVersion>(s.accountValue("SslCertDigestVersion").toInt());
+
+ QByteArray calculatedDigest;
+ switch (knownDigestVersion) {
+ case ClientAuthHandler::DigestVersion::Md5:
+ calculatedDigest = socket->peerCertificate().digest(QCryptographicHash::Md5);
+ break;
- if (knownDigest != socket->peerCertificate().digest()) {
+ case ClientAuthHandler::DigestVersion::Sha2_512:
+#if QT_VERSION >= 0x050000
+ calculatedDigest = socket->peerCertificate().digest(QCryptographicHash::Sha512);
+#else
+ calculatedDigest = sha2_512(socket->peerCertificate().toDer());
+#endif
+ break;
+
+ default:
+ qWarning() << "Certificate digest version" << QString(knownDigestVersion) << "is not supported";
+ }
+
+ if (knownDigest != calculatedDigest) {
bool accepted = false;
bool permanently = false;
emit handleSslErrors(socket, &accepted, &permanently);
bool accepted = false;
bool permanently = false;
emit handleSslErrors(socket, &accepted, &permanently);
- if (permanently)
- s.setAccountValue("SslCert", socket->peerCertificate().digest());
- else
+ if (permanently) {
+#if QT_VERSION >= 0x050000
+ s.setAccountValue("SslCert", socket->peerCertificate().digest(QCryptographicHash::Sha512));
+#else
+ s.setAccountValue("SslCert", sha2_512(socket->peerCertificate().toDer()));
+#endif
+ s.setAccountValue("SslCertDigestVersion", ClientAuthHandler::DigestVersion::Latest);
+ }
+ else {
s.setAccountValue("SslCert", QString());
s.setAccountValue("SslCert", QString());
+ s.setAccountValue("SslCertDigestVersion", QVariant(QVariant::Int));
+ }
+ }
+ else if (knownDigestVersion != ClientAuthHandler::DigestVersion::Latest) {
+#if QT_VERSION >= 0x050000
+ s.setAccountValue("SslCert", socket->peerCertificate().digest(QCryptographicHash::Sha512));
+#else
+ s.setAccountValue("SslCert", sha2_512(socket->peerCertificate().toDer()));
+#endif
+ s.setAccountValue("SslCertDigestVersion", ClientAuthHandler::DigestVersion::Latest);
}
socket->ignoreSslErrors();
}
}
socket->ignoreSslErrors();
}
+#if QT_VERSION < 0x050000
+QByteArray ClientAuthHandler::sha2_512(const QByteArray &input) {
+ unsigned char output[64];
+ sha512((unsigned char*) input.constData(), input.size(), output, false);
+ // QByteArray::fromRawData() cannot be used here because that constructor
+ // does not copy "output" and the data is clobbered when the variable goes
+ // out of scope.
+ QByteArray result;
+ result.append((char*) output, 64);
+ return result;
+}
+#endif
+
public:
ClientAuthHandler(CoreAccount account, QObject *parent = 0);
public:
ClientAuthHandler(CoreAccount account, QObject *parent = 0);
+ enum DigestVersion {
+ Md5,
+ Sha2_512,
+ Latest=Sha2_512
+ };
+
public slots:
void connectToCore();
public slots:
void connectToCore();
void checkAndEnableSsl(bool coreSupportsSsl);
void startRegistration();
void checkAndEnableSsl(bool coreSupportsSsl);
void startRegistration();
+#if QT_VERSION < 0x050000
+ QByteArray sha2_512(const QByteArray &input);
+#endif
+
private slots:
void onSocketConnected();
void onSocketStateChanged(QAbstractSocket::SocketState state);
private slots:
void onSocketConnected();
void onSocketStateChanged(QAbstractSocket::SocketState state);