Add support for Elliptic Curve keys for CertFP
authorMichael Marley <michael@michaelmarley.com>
Sat, 31 Mar 2018 18:06:16 +0000 (14:06 -0400)
committerManuel Nickschas <sputnick@quassel-irc.org>
Mon, 7 May 2018 19:03:56 +0000 (21:03 +0200)
This functionality is controlled by a feature flag so that clients
supporting EC keys won't try to set an EC key on a core that
doesn't.  As with the previous EC patch, this requires Qt 5.5 to
work but uses the QT_VERSION macro to remain compileable with Qt4.

This patch also fixes the QSsl::KeyAlgorithm indices to be correct
for both Qt4 and Qt5.  In Qt4, RSA was 0 and DSA was 1, but in Qt5
0 became Opaque, 1 because RSA, and two became DSA.  EC is 3 and
wasn't added until 5.5.  The new macro handles all three versions
correctly.  (See https://doc.qt.io/qt-5/qssl.html#KeyAlgorithm-enum
and https://doc.qt.io/archives/qt-4.8/qssl.html#KeyAlgorithm-enum.)
Thanks to @justJanne for pointing out this discrepancy.

Closes GH-347.

src/client/clientidentity.cpp
src/common/quassel.h
src/core/coreidentity.cpp
src/qtui/settingspages/identityeditwidget.cpp

index 26c0a73..3507a10 100644 (file)
@@ -111,6 +111,10 @@ void CertIdentity::markClean()
 void ClientCertManager::setSslKey(const QByteArray &encoded)
 {
     QSslKey key(encoded, QSsl::Rsa);
 void ClientCertManager::setSslKey(const QByteArray &encoded)
 {
     QSslKey key(encoded, QSsl::Rsa);
+#if QT_VERSION >= 0x050500
+    if (key.isNull() && Client::isCoreFeatureEnabled(Quassel::Feature::EcdsaCertfpKeys))
+        key = QSslKey(encoded, QSsl::Ec);
+#endif
     if (key.isNull())
         key = QSslKey(encoded, QSsl::Dsa);
     _certIdentity->setSslKey(key);
     if (key.isNull())
         key = QSslKey(encoded, QSsl::Dsa);
     _certIdentity->setSslKey(key);
index 87d525f..88b2254 100644 (file)
@@ -131,6 +131,9 @@ public:
         SenderPrefixes,           ///< Show prefixes for senders in backlog
         RemoteDisconnect,         ///< Allow this peer to be remotely disconnected
         ExtendedFeatures,         ///< Extended features
         SenderPrefixes,           ///< Show prefixes for senders in backlog
         RemoteDisconnect,         ///< Allow this peer to be remotely disconnected
         ExtendedFeatures,         ///< Extended features
+#if QT_VERSION >= 0x050500
+        EcdsaCertfpKeys,          ///< ECDSA keys for CertFP in identities
+#endif
     };
     Q_ENUMS(Feature)
 
     };
     Q_ENUMS(Feature)
 
index 1255411..b7cd6d0 100644 (file)
@@ -77,6 +77,10 @@ void CoreIdentity::synchronize(SignalProxy *proxy)
 void CoreIdentity::setSslKey(const QByteArray &encoded)
 {
     QSslKey key(encoded, QSsl::Rsa);
 void CoreIdentity::setSslKey(const QByteArray &encoded)
 {
     QSslKey key(encoded, QSsl::Rsa);
+#if QT_VERSION >= 0x050500
+    if (key.isNull())
+        key = QSslKey(encoded, QSsl::Ec);
+#endif
     if (key.isNull())
         key = QSslKey(encoded, QSsl::Dsa);
     setSslKey(key);
     if (key.isNull())
         key = QSslKey(encoded, QSsl::Dsa);
     setSslKey(key);
index a08ab09..d31020a 100644 (file)
@@ -392,7 +392,16 @@ QSslKey IdentityEditWidget::keyByFilename(const QString &filename)
     keyFile.close();
 
     for (int i = 0; i < 2; i++) {
     keyFile.close();
 
     for (int i = 0; i < 2; i++) {
+#if QT_VERSION >= 0x050500
+        // On Qt5.5+, support QSsl::KeyAlgorithm::Rsa (1), QSsl::KeyAlgorithm::Dsa (2), and QSsl::KeyAlgorithm::Ec (3)
+        for (int j = 1; j < 4; j++) {
+#elif QT_VERSION >= 0x050000
+        // On Qt5.0-Qt5.4, support QSsl::KeyAlgorithm::Rsa (1) and QSsl::KeyAlgorithm::Dsa (2) (Ec wasn't added until 5.5)
+        for (int j = 1; j < 3; j++) {
+#else
+        // On Qt4, support QSsl::KeyAlgorithm::Rsa (0) and QSsl::KeyAlgorithm::Dsa (1) (Qt4 uses different indices for the values)
         for (int j = 0; j < 2; j++) {
         for (int j = 0; j < 2; j++) {
+#endif
             key = QSslKey(keyRaw, (QSsl::KeyAlgorithm)j, (QSsl::EncodingFormat)i);
             if (!key.isNull())
                 goto returnKey;
             key = QSslKey(keyRaw, (QSsl::KeyAlgorithm)j, (QSsl::EncodingFormat)i);
             if (!key.isNull())
                 goto returnKey;
@@ -400,6 +409,12 @@ QSslKey IdentityEditWidget::keyByFilename(const QString &filename)
     }
     QMessageBox::information(this, tr("Failed to read key"), tr("Failed to read the key file. It is either incompatible or invalid. Note that the key file must not have a passphrase."));
 returnKey:
     }
     QMessageBox::information(this, tr("Failed to read key"), tr("Failed to read the key file. It is either incompatible or invalid. Note that the key file must not have a passphrase."));
 returnKey:
+#if QT_VERSION >= 0x050500
+    if(!key.isNull() && key.algorithm() == QSsl::KeyAlgorithm::Ec && !Client::isCoreFeatureEnabled(Quassel::Feature::EcdsaCertfpKeys)) {
+        QMessageBox::information(this, tr("Core does not support ECDSA keys"), tr("You loaded an ECDSA key, but the core does not support ECDSA keys. Please contact the core administrator."));
+        key.clear();
+    }
+#endif
     return key;
 }
 
     return key;
 }
 
@@ -415,11 +430,16 @@ void IdentityEditWidget::showKeyState(const QSslKey &key)
         case QSsl::Rsa:
             ui.keyTypeLabel->setText(tr("RSA"));
             break;
         case QSsl::Rsa:
             ui.keyTypeLabel->setText(tr("RSA"));
             break;
+#if QT_VERSION >= 0x050500
+        case QSsl::Ec:
+            ui.keyTypeLabel->setText(tr("ECDSA"));
+            break;
+#endif
         case QSsl::Dsa:
             ui.keyTypeLabel->setText(tr("DSA"));
             break;
         default:
         case QSsl::Dsa:
             ui.keyTypeLabel->setText(tr("DSA"));
             break;
         default:
-            ui.keyTypeLabel->setText(tr("No Key loaded"));
+            ui.keyTypeLabel->setText(tr("Invalid key or no key loaded"));
         }
         ui.clearOrLoadKeyButton->setText(tr("Clear"));
     }
         }
         ui.clearOrLoadKeyButton->setText(tr("Clear"));
     }