Also store the CACertificates of the client side certificate
authorRoeland Jago Douma <roeland@famdouma.nl>
Tue, 27 Aug 2019 07:55:41 +0000 (09:55 +0200)
committerRoeland Jago Douma <roeland@famdouma.nl>
Tue, 27 Aug 2019 07:55:41 +0000 (09:55 +0200)
Else authentication will still fail in setups that have a chain of
certificates supplied.

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
src/gui/creds/webflowcredentials.cpp
src/gui/creds/webflowcredentials.h
src/gui/wizard/flow2authcredspage.cpp
src/gui/wizard/owncloudsetuppage.cpp
src/gui/wizard/owncloudwizard.h

index b3fb845a8d367bba62068a1373a5a583ea31e131..5a7f78f936b3d34632085ddfc4514d37b3ac2beb 100644 (file)
@@ -29,6 +29,7 @@ namespace {
     const char userC[] = "user";
     const char clientCertificatePEMC[] = "_clientCertificatePEM";
     const char clientKeyPEMC[] = "_clientKeyPEM";
+    const char clientCaCertificatesPEMC[] = "_clientCaCertificatesPEM";
 } // ns
 
 class WebFlowCredentialsAccessManager : public AccessManager
@@ -56,6 +57,12 @@ protected:
             QSslConfiguration sslConfiguration = req.sslConfiguration();
             sslConfiguration.setLocalCertificate(_cred->_clientSslCertificate);
             sslConfiguration.setPrivateKey(_cred->_clientSslKey);
+
+            // Merge client side CA with system CA
+            auto ca = sslConfiguration.systemCaCertificates();
+            ca.append(_cred->_clientSslCaCertificates);
+            sslConfiguration.setCaCertificates(ca);
+
             req.setSslConfiguration(sslConfiguration);
         }
 
@@ -70,7 +77,7 @@ private:
 
 static void addSettingsToJob(Account *account, QKeychain::Job *job)
 {
-    Q_UNUSED(account);
+    Q_UNUSED(account)
     auto settings = ConfigFile::settingsWithGroup(Theme::instance()->appName());
     settings->setParent(job); // make the job parent to make setting deleted properly
     job->setSettings(settings.release());
@@ -85,11 +92,12 @@ WebFlowCredentials::WebFlowCredentials()
 
 }
 
-WebFlowCredentials::WebFlowCredentials(const QString &user, const QString &password, const QSslCertificate &certificate, const QSslKey &key)
+WebFlowCredentials::WebFlowCredentials(const QString &user, const QString &password, const QSslCertificate &certificate, const QSslKey &key, const QList<QSslCertificate> &caCertificates)
     : _user(user)
     , _password(password)
     , _clientSslKey(key)
     , _clientSslCertificate(certificate)
+    , _clientSslCaCertificates(caCertificates)
     , _ready(true)
     , _credentialsValid(true)
     , _keychainMigration(false)
@@ -163,7 +171,7 @@ void WebFlowCredentials::askFromUser() {
 }
 
 void WebFlowCredentials::slotAskFromUserCredentialsProvided(const QString &user, const QString &pass, const QString &host) {
-    Q_UNUSED(host);
+    Q_UNUSED(host)
 
     if (_user != user) {
         qCInfo(lcWebFlowCredentials()) << "Authed with the wrong user!";
@@ -246,6 +254,28 @@ void WebFlowCredentials::slotWriteClientCertPEMJobDone()
 }
 
 void WebFlowCredentials::slotWriteClientKeyPEMJobDone()
+{
+    // write ca certs if there are any
+    if (!_clientSslCaCertificates.isEmpty()) {
+        WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
+        addSettingsToJob(_account, job);
+        job->setInsecureFallback(false);
+        connect(job, &Job::finished, this, &WebFlowCredentials::slotWriteClientCaCertsPEMJobDone);
+        job->setKey(keychainKey(_account->url().toString(), _user + clientCaCertificatesPEMC, _account->id()));
+
+        QByteArray certs;
+        for(auto cert:_clientSslCaCertificates) {
+            certs += cert.toPem();
+        }
+
+        job->setBinaryData(certs);
+        job->start();
+    } else {
+        slotWriteClientCaCertsPEMJobDone();
+    }
+}
+
+void WebFlowCredentials::slotWriteClientCaCertsPEMJobDone()
 {
     WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
     addSettingsToJob(_account, job);
@@ -314,7 +344,7 @@ QString WebFlowCredentials::fetchUser() {
 }
 
 void WebFlowCredentials::slotAuthentication(QNetworkReply *reply, QAuthenticator *authenticator) {
-    Q_UNUSED(reply);
+    Q_UNUSED(reply)
 
     if (!_ready) {
         return;
@@ -415,6 +445,31 @@ void WebFlowCredentials::slotReadClientKeyPEMJobDone(QKeychain::Job *incomingJob
         }
     }
 
+    // Now fetch the actual server password
+    const QString kck = keychainKey(
+        _account->url().toString(),
+        _user + clientCaCertificatesPEMC,
+        _keychainMigration ? QString() : _account->id());
+
+    ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
+    addSettingsToJob(_account, job);
+    job->setInsecureFallback(false);
+    job->setKey(kck);
+    connect(job, &Job::finished, this, &WebFlowCredentials::slotReadClientCaCertsPEMJobDone);
+    job->start();
+}
+
+void WebFlowCredentials::slotReadClientCaCertsPEMJobDone(QKeychain::Job *incomingJob) {
+    // Store key in memory
+    ReadPasswordJob *readJob = static_cast<ReadPasswordJob *>(incomingJob);
+
+    if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
+        QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(readJob->binaryData(), QSsl::Pem);
+        if (sslCertificateList.length() >= 1) {
+            _clientSslCaCertificates = sslCertificateList;
+        }
+    }
+
     // Now fetch the actual server password
     const QString kck = keychainKey(
         _account->url().toString(),
index 197ce8b903596b38c20995ea9a54ad6dd299f10d..d9c9551bc01d155952b15a4d5bd64f652e32d47e 100644 (file)
@@ -30,7 +30,12 @@ public:
     static constexpr QNetworkRequest::Attribute DontAddCredentialsAttribute = QNetworkRequest::User;
 
     explicit WebFlowCredentials();
-    WebFlowCredentials(const QString &user, const QString &password, const QSslCertificate &certificate = QSslCertificate(), const QSslKey &key = QSslKey());
+    WebFlowCredentials(
+            const QString &user,
+            const QString &password,
+            const QSslCertificate &certificate = QSslCertificate(),
+            const QSslKey &key = QSslKey(),
+            const QList<QSslCertificate> &caCertificates = QList<QSslCertificate>());
 
     QString authType() const override;
     QString user() const override;
@@ -58,10 +63,12 @@ private slots:
 
     void slotReadClientCertPEMJobDone(QKeychain::Job *incomingJob);
     void slotReadClientKeyPEMJobDone(QKeychain::Job *incomingJob);
+    void slotReadClientCaCertsPEMJobDone(QKeychain::Job *incommingJob);
     void slotReadPasswordJobDone(QKeychain::Job *incomingJob);
 
     void slotWriteClientCertPEMJobDone();
     void slotWriteClientKeyPEMJobDone();
+    void slotWriteClientCaCertsPEMJobDone();
     void slotWriteJobDone(QKeychain::Job *);
 
 protected:
@@ -69,7 +76,8 @@ protected:
      *
      * Goes through
      *   slotReadClientCertPEMJobDone to
-     *   slotReadClientCertPEMJobDone to
+     *   slotReadClientKeyPEMJobDone to
+     *   slotReadClientCaCertsPEMJobDone to
      *   slotReadJobDone
      */
     void fetchFromKeychainHelper();
@@ -83,6 +91,7 @@ protected:
     QString _password;
     QSslKey _clientSslKey;
     QSslCertificate _clientSslCertificate;
+    QList<QSslCertificate> _clientSslCaCertificates;
 
     bool _ready;
     bool _credentialsValid;
index b52095f0da602c262bbacb3d6b139319399d272d..a368d604385a5229f12e71fe2db9a256116a3684 100644 (file)
@@ -136,7 +136,8 @@ AbstractCredentials *Flow2AuthCredsPage::getCredentials() const
                 _user,
                 _appPassword,
                 ocWizard->_clientSslCertificate,
-                ocWizard->_clientSslKey
+                ocWizard->_clientSslKey,
+                ocWizard->_clientSslCaCertificates
     );
 }
 
index 8cfa158d4c8564fb1997db4928ad435765cf4559..3a956b0d705661b31d203ec1d15af5dd27f5ce30 100644 (file)
@@ -377,12 +377,13 @@ QString subjectInfoHelper(const QSslCertificate &cert, const QByteArray &qa)
 //called during the validation of the client certificate.
 void OwncloudSetupPage::slotCertificateAccepted()
 {
-    QList<QSslCertificate> clientCaCertificates;
     QFile certFile(addCertDial->getCertificatePath());
     certFile.open(QFile::ReadOnly);
-    if (QSslCertificate::importPkcs12(&certFile,
-            &_ocWizard->_clientSslKey, &_ocWizard->_clientSslCertificate,
-            &clientCaCertificates,
+    if (QSslCertificate::importPkcs12(
+            &certFile,
+            &_ocWizard->_clientSslKey,
+            &_ocWizard->_clientSslCertificate,
+            &_ocWizard->_clientSslCaCertificates,
             addCertDial->getCertificatePasswd().toLocal8Bit())) {
         AccountPtr acc = _ocWizard->account();
 
@@ -397,7 +398,7 @@ void OwncloudSetupPage::slotCertificateAccepted()
 
         // Be sure to merge the CAs
         auto ca = sslConfiguration.systemCaCertificates();
-        ca.append(clientCaCertificates);
+        ca.append(_ocWizard->_clientSslCaCertificates);
         sslConfiguration.setCaCertificates(ca);
 
         acc->setSslConfiguration(sslConfiguration);
index c37bfd97e43dd6f80a2b5d9173a12cfe896ae9a9..c1d290d4b1b13ea2c3391a2352646b5f24300eeb 100644 (file)
@@ -78,6 +78,7 @@ public:
     // Set from the OwncloudSetupPage, later used from OwncloudHttpCredsPage
     QSslKey _clientSslKey;
     QSslCertificate _clientSslCertificate;
+    QList<QSslCertificate> _clientSslCaCertificates;
 
 public slots:
     void setAuthType(DetermineAuthTypeJob::AuthType type);