Also store the CACertificates of the client side certificate

Else authentication will still fail in setups that have a chain of
certificates supplied.

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
This commit is contained in:
Roeland Jago Douma 2019-08-27 09:55:41 +02:00
parent dbde585049
commit d584bedcb6
No known key found for this signature in database
GPG key ID: F941078878347C0C
5 changed files with 79 additions and 12 deletions

View 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(),

View 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;

View file

@ -136,7 +136,8 @@ AbstractCredentials *Flow2AuthCredsPage::getCredentials() const
_user,
_appPassword,
ocWizard->_clientSslCertificate,
ocWizard->_clientSslKey
ocWizard->_clientSslKey,
ocWizard->_clientSslCaCertificates
);
}

View 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);

View 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);