Skip to content

Commit

Permalink
allow detection and proper init of usb token for e2e encryption
Browse files Browse the repository at this point in the history
Signed-off-by: Matthieu Gallien <[email protected]>
  • Loading branch information
mgallien committed Sep 8, 2023
1 parent e05caa6 commit 3204559
Show file tree
Hide file tree
Showing 13 changed files with 253 additions and 15 deletions.
10 changes: 6 additions & 4 deletions NEXTCLOUD.cmake
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
set( APPLICATION_NAME "Nextcloud" )
set( APPLICATION_SHORTNAME "Nextcloud" )
set( APPLICATION_EXECUTABLE "nextcloud" )
set( APPLICATION_NAME "NextcloudDev" )
set( APPLICATION_SHORTNAME "NextDev" )
set( APPLICATION_EXECUTABLE "nextclouddev" )
set( APPLICATION_CONFIG_NAME "${APPLICATION_EXECUTABLE}" )
set( APPLICATION_DOMAIN "nextcloud.com" )
set( APPLICATION_VENDOR "Nextcloud GmbH" )
Expand All @@ -11,7 +11,7 @@ if(APPLE AND APPLICATION_NAME STREQUAL "Nextcloud" AND EXISTS "${CMAKE_SOURCE_DI
set( APPLICATION_ICON_NAME "Nextcloud-macOS" )
message("Using macOS-specific application icon: ${APPLICATION_ICON_NAME}")
else()
set( APPLICATION_ICON_NAME "${APPLICATION_SHORTNAME}" )
set( APPLICATION_ICON_NAME "Nextcloud" )
endif()

set( APPLICATION_ICON_SET "SVG" )
Expand Down Expand Up @@ -80,3 +80,5 @@ endif()
if (APPLE)
option( BUILD_FILE_PROVIDER_MODULE "Build the macOS virtual files File Provider module" OFF )
endif()

set (CLIENTSIDEENCRYPTION_ENFORCE_USB_TOKEN true)
2 changes: 2 additions & 0 deletions config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,6 @@

#cmakedefine CFAPI_SHELL_EXTENSIONS_LIB_NAME "@CFAPI_SHELL_EXTENSIONS_LIB_NAME@"

#cmakedefine CLIENTSIDEENCRYPTION_ENFORCE_USB_TOKEN @CLIENTSIDEENCRYPTION_ENFORCE_USB_TOKEN@

#endif
9 changes: 9 additions & 0 deletions src/gui/accountsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ 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());
Expand All @@ -291,6 +292,7 @@ void AccountSettings::slotE2eEncryptionGenerateKeys()
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 @@ -301,6 +303,13 @@ 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());
}

void AccountSettings::slotEncryptFolderFinished(int status)
{
qCInfo(lcAccountSettings) << "Current folder encryption status code:" << status;
Expand Down
1 change: 1 addition & 0 deletions src/gui/accountsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ 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
39 changes: 39 additions & 0 deletions src/gui/systray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,45 @@ void Systray::createFileActivityDialog(const QString &localPath)
Q_EMIT showFileDetailsPage(localPath, FileDetailsPage::Activity);
}

void Systray::createTokenInitDialog(const QVariantList &tokensInfo)
{
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},
};

QQmlComponent tokenInitDialogComponent(_trayEngine, QStringLiteral("qrc:/qml/src/gui/filedetails/FileDetailsWindow.qml"));

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

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

_tokenInitDialog = dialog;

_tokenInitDialog->show();
_tokenInitDialog->raise();
_tokenInitDialog->requestActivate();
} else {
qCWarning(lcSystray) << tokenInitDialogComponent.errorString();
}
}

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

#include <QSystemTrayIcon>

#include "accountmanager.h"
#include "tray/usermodel.h"

#include <QSystemTrayIcon>
#include <QQuickImageProvider>
#include <QQmlNetworkAccessManagerFactory>

class QScreen;
Expand Down Expand Up @@ -145,6 +145,7 @@ public slots:

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

void presentShareViewInTray(const QString &localPath);

Expand Down Expand Up @@ -185,6 +186,7 @@ private slots:
QSet<qlonglong> _callsAlreadyNotified;
QPointer<QObject> _editFileLocallyLoadingDialog;
QVector<QQuickWindow*> _fileDetailDialogs;
QQuickWindow* _tokenInitDialog = nullptr;
};

} // namespace OCC
Expand Down
2 changes: 2 additions & 0 deletions src/libsync/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ set(libsync_SRCS
clientsideencryption.cpp
clientsideencryptionjobs.h
clientsideencryptionjobs.cpp
clientsidetokenselector.h
clientsidetokenselector.cpp
datetimeprovider.h
datetimeprovider.cpp
ocsuserstatusconnector.h
Expand Down
9 changes: 6 additions & 3 deletions src/libsync/account.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
#include "clientsideencryption.h"
#include "ocsuserstatusconnector.h"

#include "config.h"

#include <QLoggingCategory>
#include <QNetworkReply>
#include <QNetworkAccessManager>
Expand Down Expand Up @@ -1023,14 +1025,15 @@ bool Account::askUserForMnemonic() const
return _e2eAskUserForMnemonic;
}

bool Account::useHardwareTokenEncryption() const
bool Account::enforceUseHardwareTokenEncryption() const
{
return !encryptionHardwareTokenDriverPath().isEmpty();
return CLIENTSIDEENCRYPTION_ENFORCE_USB_TOKEN;
}

QString Account::encryptionHardwareTokenDriverPath() const
{
return {};
return QStringLiteral("/home/mgallien/work/nextcloud/Gemalto Safenet eToken 10.8.1050/data/usr/lib/libIDPrimeTokenEngine.so.10.8.1050");
// return {};
}

void Account::setAskUserForMnemonic(const bool ask)
Expand Down
6 changes: 3 additions & 3 deletions src/libsync/account.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class OWNCLOUDSYNC_EXPORT Account : public QObject
Q_PROPERTY(QUrl url MEMBER _url)
Q_PROPERTY(bool e2eEncryptionKeysGenerationAllowed MEMBER _e2eEncryptionKeysGenerationAllowed)
Q_PROPERTY(bool askUserForMnemonic READ askUserForMnemonic WRITE setAskUserForMnemonic NOTIFY askUserForMnemonicChanged)
Q_PROPERTY(bool useHardwareTokenEncryption READ useHardwareTokenEncryption NOTIFY useHardwareTokenEncryptionChanged)
Q_PROPERTY(bool enforceUseHardwareTokenEncryption READ enforceUseHardwareTokenEncryption NOTIFY enforceUseHardwareTokenEncryptionChanged)
Q_PROPERTY(QString encryptionHardwareTokenDriverPath READ encryptionHardwareTokenDriverPath NOTIFY encryptionHardwareTokenDriverPathChanged)

public:
Expand Down Expand Up @@ -328,7 +328,7 @@ class OWNCLOUDSYNC_EXPORT Account : public QObject

[[nodiscard]] bool askUserForMnemonic() const;

[[nodiscard]] bool useHardwareTokenEncryption() const;
[[nodiscard]] bool enforceUseHardwareTokenEncryption() const;

[[nodiscard]] QString encryptionHardwareTokenDriverPath() const;

Expand Down Expand Up @@ -360,7 +360,7 @@ public slots:
void accountChangedDisplayName();
void prettyNameChanged();
void askUserForMnemonicChanged();
void useHardwareTokenEncryptionChanged();
void enforceUseHardwareTokenEncryptionChanged();
void encryptionHardwareTokenDriverPathChanged();

/// Used in RemoteWipe
Expand Down
26 changes: 23 additions & 3 deletions src/libsync/clientsideencryption.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1012,13 +1012,22 @@ std::optional<QByteArray> decryptStringAsymmetricWithToken(ENGINE *sslEngine,
}


ClientSideEncryption::ClientSideEncryption() = default;
ClientSideEncryption::ClientSideEncryption()
{
connect(&_usbTokenInformation, &ClientSideTokenSelector::discoveredTokensChanged,
this, &ClientSideEncryption::displayTokenInitDialog);
}

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

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

const QSslKey &ClientSideEncryption::getPublicKey() const
{
return _publicKey;
Expand Down Expand Up @@ -1080,8 +1089,19 @@ void ClientSideEncryption::initialize(const AccountPtr &account)
return;
}

if (account->useHardwareTokenEncryption()) {
initializeHardwareTokenEncryption(account);
if (account->enforceUseHardwareTokenEncryption()) {
if (_usbTokenInformation.isSetup()) {
initializeHardwareTokenEncryption(account);
} else if (account->e2eEncryptionKeysGenerationAllowed() && account->askUserForMnemonic()) {
_usbTokenInformation.searchForToken();
if (_usbTokenInformation.isSetup()) {
initializeHardwareTokenEncryption(account);
} else {
emit initializationFinished();
}
} else {
emit initializationFinished();
}
} else {
fetchCertificateFromKeyChain(account);
}
Expand Down
9 changes: 9 additions & 0 deletions src/libsync/clientsideencryption.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
#define CLIENTSIDEENCRYPTION_H

#include "accountfwd.h"

#include "networkjobs.h"
#include "clientsidetokenselector.h"

#include <QString>
#include <QObject>
Expand Down Expand Up @@ -139,6 +141,10 @@ class OWNCLOUDSYNC_EXPORT ClientSideEncryption : public QObject {

[[nodiscard]] bool isInitialized() const;

[[nodiscard]] bool tokenIsSetup() const;

[[nodiscard]] QVariantList discoveredTokens() const;

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

void setPublicKey(const QSslKey &publicKey);
Expand Down Expand Up @@ -166,6 +172,7 @@ class OWNCLOUDSYNC_EXPORT ClientSideEncryption : public QObject {
void certificateDeleted();
void mnemonicDeleted();
void publicKeyDeleted();
void displayTokenInitDialog();

public slots:
void initialize(const OCC::AccountPtr &account);
Expand Down Expand Up @@ -248,6 +255,8 @@ private slots:
QString _mnemonic;
bool _newMnemonicGenerated = false;

ClientSideTokenSelector _usbTokenInformation;

PKCS11_KEY* _tokenPublicKey = nullptr;
PKCS11_KEY* _tokenPrivateKey = nullptr;
};
Expand Down
95 changes: 95 additions & 0 deletions src/libsync/clientsidetokenselector.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*

Check notice on line 1 in src/libsync/clientsidetokenselector.cpp

View workflow job for this annotation

GitHub Actions / build

Run clang-format on src/libsync/clientsidetokenselector.cpp

File src/libsync/clientsidetokenselector.cpp (lines 30, 72, 73, 88, 90): Code does not conform to Custom style guidelines.
* Copyright © 2023, Matthieu Gallien <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/

#define OPENSSL_SUPPRESS_DEPRECATED

#include "clientsidetokenselector.h"

#include <QLoggingCategory>

#include <libp11.h>

namespace OCC
{

Q_LOGGING_CATEGORY(lcCseSelector, "nextcloud.sync.clientsideencryption.selector", QtInfoMsg)

ClientSideTokenSelector::ClientSideTokenSelector(QObject *parent)
: QObject{parent}
{

}

bool ClientSideTokenSelector::isSetup() const
{
return false;
}

QVariantList ClientSideTokenSelector::discoveredTokens() const
{
return _discoveredTokens;
}

void failedToInitialize(std::nullptr_t)
{
}

void ClientSideTokenSelector::searchForToken()
{
auto account = nullptr;
auto ctx = PKCS11_CTX_new();

auto rc = PKCS11_CTX_load(ctx, "opensc-pkcs11.so");
if (rc) {
qCWarning(lcCseSelector()) << "loading pkcs11 engine failed:" << ERR_reason_error_string(ERR_get_error());

failedToInitialize(account);
return;
}

auto tokensCount = 0u;
PKCS11_SLOT *tokenSlots = nullptr;
/* get information on all slots */
if (PKCS11_enumerate_slots(ctx, &tokenSlots, &tokensCount) < 0) {
qCWarning(lcCseSelector()) << "no slots available" << ERR_reason_error_string(ERR_get_error());

failedToInitialize(account);
return;
}

_discoveredTokens.clear();
auto currentSlot = static_cast<PKCS11_SLOT*>(nullptr);
for(auto i = 0u; i < tokensCount; ++i) {
currentSlot = PKCS11_find_next_token(ctx, tokenSlots, tokensCount, currentSlot);
if (currentSlot == nullptr || currentSlot->token == nullptr) {
qCWarning(lcCseSelector()) << "no token available" << ERR_reason_error_string(ERR_get_error());

failedToInitialize(account);
return;
}
qCInfo(lcCseSelector()) << "Slot manufacturer......:" << currentSlot->manufacturer;
qCInfo(lcCseSelector()) << "Slot description.......:" << currentSlot->description;
qCInfo(lcCseSelector()) << "Slot token label.......:" << currentSlot->token->label;
qCInfo(lcCseSelector()) << "Slot token manufacturer:" << currentSlot->token->manufacturer;
qCInfo(lcCseSelector()) << "Slot token model.......:" << currentSlot->token->model;
qCInfo(lcCseSelector()) << "Slot token serialnr....:" << currentSlot->token->serialnr;

_discoveredTokens.push_back(QVariantMap{{QStringLiteral("manufacturer"), QString::fromLatin1(currentSlot->manufacturer)},
{QStringLiteral("description"), QString::fromLatin1(currentSlot->description)},
{QStringLiteral("label"), QString::fromLatin1(currentSlot->token->label)},});
}
emit discoveredTokensChanged();
}

}
Loading

0 comments on commit 3204559

Please sign in to comment.