Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

validate certificate for E2EE against private key #4949

Merged
merged 7 commits into from
Oct 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 32 additions & 9 deletions src/libsync/clientsideencryption.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,9 @@ namespace {
EVP_PKEY_CTX* _ctx = nullptr;
};

class PKey {
}

class ClientSideEncryption::PKey {
public:
~PKey()
{
Expand Down Expand Up @@ -255,6 +257,8 @@ namespace {
EVP_PKEY* _pkey = nullptr;
};

namespace
{
class X509Certificate {
public:
~X509Certificate()
Expand Down Expand Up @@ -619,7 +623,7 @@ QByteArray decryptStringSymmetric(const QByteArray& key, const QByteArray& data)
QByteArray privateKeyToPem(const QByteArray key) {
Bio privateKeyBio;
BIO_write(privateKeyBio, key.constData(), key.size());
auto pkey = PKey::readPrivateKey(privateKeyBio);
auto pkey = ClientSideEncryption::PKey::readPrivateKey(privateKeyBio);

Bio pemBio;
PEM_write_bio_PKCS8PrivateKey(pemBio, pkey, nullptr, nullptr, 0, nullptr, nullptr);
Expand Down Expand Up @@ -1123,10 +1127,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();
Expand Down Expand Up @@ -1181,14 +1185,33 @@ void ClientSideEncryption::generateCSR(const AccountPtr &account, EVP_PKEY *keyP
qCInfo(lcCse()) << "Returning the certificate";
qCInfo(lcCse()) << output;

sendSignRequestCSR(account, std::move(keyPair), output);
}

void ClientSideEncryption::sendSignRequestCSR(const AccountPtr &account, PKey keyPair, const QByteArray &csrContent)
{
auto job = new SignPublicKeyApiJob(account, e2eeBaseUrl() + "public-key", this);
job->setCsr(output);
job->setCsr(csrContent);

connect(job, &SignPublicKeyApiJob::jsonReceived, [this, account](const QJsonDocument& json, int retCode) {
connect(job, &SignPublicKeyApiJob::jsonReceived, [this, account, keyPair = std::move(keyPair)](const QJsonDocument& json, const int retCode) {
if (retCode == 200) {
QString cert = json.object().value("ocs").toObject().value("data").toObject().value("public-key").toString();
const auto cert = json.object().value("ocs").toObject().value("data").toObject().value("public-key").toString();
_certificate = QSslCertificate(cert.toLocal8Bit(), QSsl::Pem);
_publicKey = _certificate.publicKey();
Bio certificateBio;
const auto certificatePem = _certificate.toPem();
BIO_write(certificateBio, certificatePem.constData(), certificatePem.size());
const auto x509Certificate = X509Certificate::readCertificate(certificateBio);
if (!X509_check_private_key(x509Certificate, keyPair)) {
auto lastError = ERR_get_error();
while (lastError) {
qCInfo(lcCse()) << ERR_lib_error_string(lastError);
lastError = ERR_get_error();
}
forgetSensitiveData(account);
return;
}
qCInfo(lcCse()) << "received a valid certificate";
fetchAndValidatePublicKeyFromServer(account);
}
qCInfo(lcCse()) << retCode;
Expand Down Expand Up @@ -1475,7 +1498,7 @@ QByteArray FolderMetadata::encryptMetadataKey(const QByteArray& data) const
Bio publicKeyBio;
QByteArray publicKeyPem = _account->e2e()->_publicKey.toPem();
BIO_write(publicKeyBio, publicKeyPem.constData(), publicKeyPem.size());
auto publicKey = PKey::readPublicKey(publicKeyBio);
auto publicKey = ClientSideEncryption::PKey::readPublicKey(publicKeyBio);

// The metadata key is binary so base64 encode it first
return EncryptionHelper::encryptStringAsymmetric(publicKey, data.toBase64());
Expand All @@ -1486,7 +1509,7 @@ QByteArray FolderMetadata::decryptMetadataKey(const QByteArray& encryptedMetadat
Bio privateKeyBio;
QByteArray privateKeyPem = _account->e2e()->_privateKey;
BIO_write(privateKeyBio, privateKeyPem.constData(), privateKeyPem.size());
auto key = PKey::readPrivateKey(privateKeyBio);
auto key = ClientSideEncryption::PKey::readPrivateKey(privateKeyBio);

// Also base64 decode the result
QByteArray decryptResult = EncryptionHelper::decryptStringAsymmetric(
Expand Down
5 changes: 4 additions & 1 deletion src/libsync/clientsideencryption.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,15 @@ class OWNCLOUDSYNC_EXPORT StreamingDecryptor
class OWNCLOUDSYNC_EXPORT ClientSideEncryption : public QObject {
Q_OBJECT
public:
class PKey;

ClientSideEncryption();
void initialize(const AccountPtr &account);

private:
void generateKeyPair(const AccountPtr &account);
void generateCSR(const AccountPtr &account, EVP_PKEY *keyPair);
void generateCSR(const AccountPtr &account, PKey keyPair);
void sendSignRequestCSR(const AccountPtr &account, PKey keyPair, const QByteArray &csrContent);
void encryptPrivateKey(const AccountPtr &account);

public:
Expand Down