From 1ec7774e2f814cdd8e1b0529cf17619a96701b14 Mon Sep 17 00:00:00 2001 From: Matthieu Gallien Date: Fri, 16 Sep 2022 18:20:41 +0200 Subject: [PATCH] validate certificate for E2EE against private key Signed-off-by: Matthieu Gallien --- src/libsync/clientsideencryption.cpp | 33 +++++++++++++++++++++++++--- src/libsync/clientsideencryption.h | 6 ++++- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/libsync/clientsideencryption.cpp b/src/libsync/clientsideencryption.cpp index a9a81b1a2..29b56c4b8 100644 --- a/src/libsync/clientsideencryption.cpp +++ b/src/libsync/clientsideencryption.cpp @@ -1123,10 +1123,10 @@ void ClientSideEncryption::generateKeyPair(const AccountPtr &account) _privateKey = key; qCInfo(lcCse()) << "Keys generated correctly, sending to server."; - generateCSR(account, localKeyPair); + generateCSR(account, std::move(localKeyPair)); } -void ClientSideEncryption::generateCSR(const AccountPtr &account, EVP_PKEY *keyPair) +void ClientSideEncryption::generateCSR(const AccountPtr &account, PKey keyPair) { // OpenSSL expects const char. auto cnArray = account->davUser().toLocal8Bit(); @@ -1184,11 +1184,38 @@ void ClientSideEncryption::generateCSR(const AccountPtr &account, EVP_PKEY *keyP auto job = new SignPublicKeyApiJob(account, e2eeBaseUrl() + "public-key", this); job->setCsr(output); - connect(job, &SignPublicKeyApiJob::jsonReceived, [this, account](const QJsonDocument& json, int retCode) { + connect(job, &SignPublicKeyApiJob::jsonReceived, [this, account, keyPair = std::move(keyPair)](const QJsonDocument& json, int retCode) { if (retCode == 200) { QString cert = json.object().value("ocs").toObject().value("data").toObject().value("public-key").toString(); _certificate = QSslCertificate(cert.toLocal8Bit(), QSsl::Pem); _publicKey = _certificate.publicKey(); + + const auto publicKeyString = cert.toLocal8Bit(); + Bio serverPublicKeyBio; + BIO_write(serverPublicKeyBio, publicKeyString.constData(), publicKeyString.size()); + const auto serverPublicKey = PKey::readPrivateKey(serverPublicKeyBio); + + Bio certificateBio; + const auto certificatePem = _certificate.toPem(); + BIO_write(certificateBio, certificatePem.constData(), certificatePem.size()); + const auto x509Certificate = X509Certificate::readCertificate(certificateBio); + + if (auto certificateCheckResult = X509_check_private_key(x509Certificate, keyPair) ; !certificateCheckResult) { + std::array buffer; + qCInfo(lcCse()) << "X509_check_private_key" << certificateCheckResult; + + unsigned long lastError = 1; + while (lastError) { + lastError = ERR_get_error(); + qCInfo(lcCse()) << ERR_error_string(lastError, buffer.data()); + } + + forgetSensitiveData(account); + return; + } + + qCInfo(lcCse()) << "received a valid certificate"; + fetchAndValidatePublicKeyFromServer(account); } qCInfo(lcCse()) << retCode; diff --git a/src/libsync/clientsideencryption.h b/src/libsync/clientsideencryption.h index b628492b8..b3f6079fe 100644 --- a/src/libsync/clientsideencryption.h +++ b/src/libsync/clientsideencryption.h @@ -113,6 +113,10 @@ private: }; } +namespace { +class PKey; +} + class OWNCLOUDSYNC_EXPORT ClientSideEncryption : public QObject { Q_OBJECT public: @@ -121,7 +125,7 @@ public: private: void generateKeyPair(const AccountPtr &account); - void generateCSR(const AccountPtr &account, EVP_PKEY *keyPair); + void generateCSR(const AccountPtr &account, PKey keyPair); void encryptPrivateKey(const AccountPtr &account); public: