Skip to content

Commit

Permalink
allow to select and store the certificate to use for e2e
Browse files Browse the repository at this point in the history
Signed-off-by: Matthieu Gallien <[email protected]>
  • Loading branch information
mgallien committed Nov 24, 2023
1 parent d687da8 commit 2cedc8e
Show file tree
Hide file tree
Showing 11 changed files with 228 additions and 235 deletions.
12 changes: 8 additions & 4 deletions src/gui/EncryptionTokenSelectionWindow.qml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ import "./tray"
ApplicationWindow {
id: encryptionKeyChooserDialog

required property var tokensInfo
required property var keysInfo
required property var certificatesInfo
required property ClientSideTokenSelector certificateSelector
property string selectedSerialNumber: ''

flags: Qt.Window | Qt.Dialog
visible: true
Expand Down Expand Up @@ -94,18 +95,19 @@ ApplicationWindow {
currentIndex: -1

model: DelegateModel {
model: keysInfo
model: certificatesInfo

delegate: ItemDelegate {
width: tokensListView.contentItem.width

text: modelData.label
text: modelData.subject

highlighted: tokensListView.currentIndex === index

onClicked: function()
{
tokensListView.currentIndex = index
selectedSerialNumber = modelData.serialNumber
}
}
}
Expand All @@ -126,10 +128,12 @@ ApplicationWindow {

onAccepted: function() {
Systray.destroyDialog(encryptionKeyChooserDialog)
certificateSelector.serialNumber = selectedSerialNumber
}

onRejected: function() {
Systray.destroyDialog(encryptionKeyChooserDialog)
certificateSelector.serialNumber = ''
}
}
}
Expand Down
14 changes: 2 additions & 12 deletions src/gui/accountsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,16 +283,14 @@ void AccountSettings::slotE2eEncryptionMnemonicReady()
void AccountSettings::slotE2eEncryptionGenerateKeys()
{
connect(_accountState->account()->e2e(), &ClientSideEncryption::initializationFinished, this, &AccountSettings::slotE2eEncryptionInitializationFinished);
connect(_accountState->account()->e2e(), &ClientSideEncryption::displayTokenInitDialog, this, &AccountSettings::slotDisplayTokenInitDialog);
_accountState->account()->setE2eEncryptionKeysGenerationAllowed(true);
_accountState->account()->setAskUserForMnemonic(true);
_accountState->account()->e2e()->initialize(_accountState->account());
_accountState->account()->e2e()->initialize(this, _accountState->account());
}

void AccountSettings::slotE2eEncryptionInitializationFinished(bool isNewMnemonicGenerated)
{
disconnect(_accountState->account()->e2e(), &ClientSideEncryption::initializationFinished, this, &AccountSettings::slotE2eEncryptionInitializationFinished);
disconnect(_accountState->account()->e2e(), &ClientSideEncryption::displayTokenInitDialog, this, &AccountSettings::slotDisplayTokenInitDialog);
if (_accountState->account()->e2e()->isInitialized()) {
removeActionFromEncryptionMessage(e2EeUiActionEnableEncryptionId);
slotE2eEncryptionMnemonicReady();
Expand All @@ -303,14 +301,6 @@ void AccountSettings::slotE2eEncryptionInitializationFinished(bool isNewMnemonic
_accountState->account()->setAskUserForMnemonic(false);
}

void AccountSettings::slotDisplayTokenInitDialog()
{
disconnect(_accountState->account()->e2e(), &ClientSideEncryption::initializationFinished, this, &AccountSettings::slotE2eEncryptionInitializationFinished);
disconnect(_accountState->account()->e2e(), &ClientSideEncryption::displayTokenInitDialog, this, &AccountSettings::slotDisplayTokenInitDialog);
Systray::instance()->createTokenInitDialog(_accountState->account()->e2e()->discoveredTokens(),
_accountState->account()->e2e()->discoveredKeys());
}

void AccountSettings::slotEncryptFolderFinished(int status)
{
qCInfo(lcAccountSettings) << "Current folder encryption status code:" << status;
Expand Down Expand Up @@ -1640,7 +1630,7 @@ void AccountSettings::initializeE2eEncryption()
}
});
_accountState->account()->setE2eEncryptionKeysGenerationAllowed(false);
_accountState->account()->e2e()->initialize(_accountState->account());
_accountState->account()->e2e()->initialize(this, _accountState->account());
}
}

Expand Down
1 change: 0 additions & 1 deletion src/gui/accountsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ protected slots:
void slotE2eEncryptionMnemonicReady();
void slotE2eEncryptionGenerateKeys();
void slotE2eEncryptionInitializationFinished(bool isNewMnemonicGenerated);
void slotDisplayTokenInitDialog();
void slotEncryptFolderFinished(int status);

void slotSelectiveSyncChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
Expand Down
2 changes: 1 addition & 1 deletion src/gui/connectionvalidator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ void ConnectionValidator::slotUserFetched(UserInfo *userInfo)

#ifndef TOKEN_AUTH_ONLY
connect(_account->e2e(), &ClientSideEncryption::initializationFinished, this, &ConnectionValidator::reportConnected);
_account->e2e()->initialize(_account);
_account->e2e()->initialize(nullptr, _account);
#else
reportResult(Connected);
#endif
Expand Down
1 change: 1 addition & 0 deletions src/gui/owncloudgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ ownCloudGui::ownCloudGui(Application *parent)
qmlRegisterUncreatableType<UnifiedSearchResultsListModel>("com.nextcloud.desktopclient", 1, 0, "UnifiedSearchResultsListModel", "UnifiedSearchResultsListModel");
qmlRegisterUncreatableType<UserStatus>("com.nextcloud.desktopclient", 1, 0, "UserStatus", "Access to Status enum");
qmlRegisterUncreatableType<Sharee>("com.nextcloud.desktopclient", 1, 0, "Sharee", "Access to Type enum");
qmlRegisterUncreatableType<ClientSideTokenSelector>("com.nextcloud.desktopclient", 1, 0, "ClientSideTokenSelector", "Access to the certificate selector");

qRegisterMetaTypeStreamOperators<Emoji>();

Expand Down
46 changes: 2 additions & 44 deletions src/gui/systray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "configfile.h"
#include "accessmanager.h"
#include "callstatechecker.h"
#include "clientsidetokenselector.h"

#include <QCursor>
#include <QGuiApplication>
Expand All @@ -35,6 +36,7 @@
#include <QMenu>
#include <QGuiApplication>
#include <QQuickView>
#include <QMessageBox>

#ifdef USE_FDO_NOTIFICATIONS
#include <QDBusConnection>
Expand Down Expand Up @@ -413,50 +415,6 @@ void Systray::createFileActivityDialog(const QString &localPath)
Q_EMIT showFileDetailsPage(localPath, FileDetailsPage::Activity);
}

void Systray::createTokenInitDialog(const QVariantList &tokensInfo,
const QVariantList &keysInfo)
{
if(_tokenInitDialog) {
destroyDialog(_tokenInitDialog);
_tokenInitDialog = nullptr;
}

qCDebug(lcSystray) << "Opening new token init dialog with " << tokensInfo.size() << "possible tokens";

if (!_trayEngine) {
qCWarning(lcSystray) << "Could not open token init dialog as no tray engine was available";
return;
}

const QVariantMap initialProperties{
{"tokensInfo", tokensInfo},
{"keysInfo", keysInfo}
};

QQmlComponent encryptionTokenDialog(_trayEngine, QStringLiteral("qrc:/qml/src/gui/EncryptionTokenSelectionWindow.qml"));

if (!encryptionTokenDialog.isError()) {
const auto createdDialog = encryptionTokenDialog.createWithInitialProperties(initialProperties);
const auto dialog = qobject_cast<QQuickWindow*>(createdDialog);

if(!dialog) {
qCWarning(lcSystray) << "File details dialog window resulted in creation of object that was not a window!";
return;
}

_tokenInitDialog = dialog;

Q_EMIT hideSettingsDialog();

dialog->show();
dialog->raise();
dialog->requestActivate();

} else {
qCWarning(lcSystray) << encryptionTokenDialog.errorString();
}
}

void Systray::presentShareViewInTray(const QString &localPath)
{
const auto folder = FolderMan::instance()->folderForPath(localPath);
Expand Down
4 changes: 2 additions & 2 deletions src/gui/systray.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class QGuiApplication;

namespace OCC {

class ClientSideTokenSelector;

class AccessManagerFactory : public QQmlNetworkAccessManagerFactory
{
public:
Expand Down Expand Up @@ -147,8 +149,6 @@ public slots:

void createShareDialog(const QString &localPath);
void createFileActivityDialog(const QString &localPath);
void createTokenInitDialog(const QVariantList &tokensInfo,
const QVariantList &keysInfo);

void presentShareViewInTray(const QString &localPath);

Expand Down
64 changes: 45 additions & 19 deletions src/libsync/clientsideencryption.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <QXmlStreamNamespaceDeclaration>
#include <QStack>
#include <QInputDialog>
#include <QWidget>
#include <QLineEdit>
#include <QIODevice>
#include <QUuid>
Expand Down Expand Up @@ -1014,23 +1015,13 @@ std::optional<QByteArray> decryptStringAsymmetricWithToken(ENGINE *sslEngine,

ClientSideEncryption::ClientSideEncryption()
{
connect(&_usbTokenInformation, &ClientSideTokenSelector::discoveredTokensChanged,
this, &ClientSideEncryption::displayTokenInitDialog);
connect(&_usbTokenInformation, &ClientSideTokenSelector::discoveredCertificatesChanged,
this, &ClientSideEncryption::completeHardwareTokenInitialization);
}

bool ClientSideEncryption::isInitialized() const
{
return !getMnemonic().isEmpty();
}

QVariantList ClientSideEncryption::discoveredTokens() const
{
return _usbTokenInformation.discoveredTokens();
}

QVariantList ClientSideEncryption::discoveredKeys() const
{
return _usbTokenInformation.discoveredKeys();
return useTokenBasedEncryption() || !getMnemonic().isEmpty();
}

const QSslKey &ClientSideEncryption::getPublicKey() const
Expand Down Expand Up @@ -1083,7 +1074,13 @@ ENGINE* ClientSideEncryption::sslEngine() const
return ENGINE_get_default_RSA();
}

void ClientSideEncryption::initialize(const AccountPtr &account)
ClientSideTokenSelector *ClientSideEncryption::usbTokenInformation()
{
return &_usbTokenInformation;
}

void ClientSideEncryption::initialize(QWidget *settingsDialog,
const AccountPtr &account)
{
Q_ASSERT(account);

Expand All @@ -1096,11 +1093,11 @@ void ClientSideEncryption::initialize(const AccountPtr &account)

if (account->enforceUseHardwareTokenEncryption()) {
if (_usbTokenInformation.isSetup()) {
initializeHardwareTokenEncryption(account);
initializeHardwareTokenEncryption(settingsDialog, account);
} else if (account->e2eEncryptionKeysGenerationAllowed() && account->askUserForMnemonic()) {
_usbTokenInformation.searchForToken(account);
_usbTokenInformation.searchForCertificates(account);
if (_usbTokenInformation.isSetup()) {
initializeHardwareTokenEncryption(account);
initializeHardwareTokenEncryption(settingsDialog, account);
} else {
emit initializationFinished();
}
Expand All @@ -1112,7 +1109,8 @@ void ClientSideEncryption::initialize(const AccountPtr &account)
}
}

void ClientSideEncryption::initializeHardwareTokenEncryption(const AccountPtr &account)
void ClientSideEncryption::initializeHardwareTokenEncryption(QWidget *settingsDialog,
const AccountPtr &account)
{
auto ctx = PKCS11_CTX_new();

Expand Down Expand Up @@ -1157,7 +1155,18 @@ void ClientSideEncryption::initializeHardwareTokenEncryption(const AccountPtr &a
}

/* perform pkcs #11 login */
QByteArray password = "0000";
bool ok;
QString text = QInputDialog::getText(settingsDialog, tr("QInputDialog::getText()"),
tr("User name:"), QLineEdit::Normal,
QDir::home().dirName(), &ok);
if (!ok || text.isEmpty()) {
qCWarning(lcCse()) << "an USER pin is required";

failedToInitialize(account);
return;
}

const auto password = text.toLatin1();
if (PKCS11_login(slot, 0, password.data()) != 0) {
qCWarning(lcCse()) << "PKCS11_login failed" << ERR_reason_error_string(ERR_get_error());

Expand Down Expand Up @@ -1518,6 +1527,23 @@ void ClientSideEncryption::writeCertificate(const AccountPtr &account)
job->start();
}

void ClientSideEncryption::completeHardwareTokenInitialization()
{
for (const auto &oneCertificate : _usbTokenInformation.discoveredCertificates()) {
const auto certificateData = oneCertificate.toMap();
const auto sslCertificate = certificateData[QStringLiteral("certificate")].value<QSslCertificate>();
if (sslCertificate.isNull()) {
qCDebug(lcCse()) << "null certificate";
continue;
}
const auto sslErrors = QSslCertificate::verify({sslCertificate});
for (const auto &oneError : sslErrors) {
qCInfo(lcCse()) << oneError;
}
qCInfo(lcCse()) << "certificate is valid" << certificateData[QStringLiteral("serialNumber")] << certificateData[QStringLiteral("issuer")];
}
}

void ClientSideEncryption::generateMnemonic()
{
const auto list = WordList::getRandomWords(12);
Expand Down
19 changes: 11 additions & 8 deletions src/libsync/clientsideencryption.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@

#include <optional>

class QWidget;

namespace QKeychain {
class Job;
class WritePasswordJob;
Expand Down Expand Up @@ -143,10 +145,6 @@ class OWNCLOUDSYNC_EXPORT ClientSideEncryption : public QObject {

[[nodiscard]] bool tokenIsSetup() const;

[[nodiscard]] QVariantList discoveredTokens() const;

[[nodiscard]] QVariantList discoveredKeys() const;

[[nodiscard]] const QSslKey& getPublicKey() const;

void setPublicKey(const QSslKey &publicKey);
Expand All @@ -165,7 +163,9 @@ class OWNCLOUDSYNC_EXPORT ClientSideEncryption : public QObject {

void setCertificate(const QSslCertificate &certificate);

ENGINE* sslEngine() const;
[[nodiscard]] ENGINE* sslEngine() const;

[[nodiscard]] ClientSideTokenSelector* usbTokenInformation();

signals:
void initializationFinished(bool isNewMnemonicGenerated = false);
Expand All @@ -174,11 +174,12 @@ class OWNCLOUDSYNC_EXPORT ClientSideEncryption : public QObject {
void certificateDeleted();
void mnemonicDeleted();
void publicKeyDeleted();
void displayTokenInitDialog();

public slots:
void initialize(const OCC::AccountPtr &account);
void initializeHardwareTokenEncryption(const AccountPtr &account);
void initialize(QWidget *settingsDialog,
const OCC::AccountPtr &account);
void initializeHardwareTokenEncryption(QWidget* settingsDialog,
const OCC::AccountPtr &account);
void forgetSensitiveData(const OCC::AccountPtr &account);

private slots:
Expand Down Expand Up @@ -206,6 +207,8 @@ private slots:
void writePrivateKey(const OCC::AccountPtr &account);
void writeCertificate(const OCC::AccountPtr &account);

void completeHardwareTokenInitialization();

private:
void generateMnemonic();

Expand Down
Loading

0 comments on commit 2cedc8e

Please sign in to comment.