diff --git a/src/gui/EncryptionTokenSelectionWindow.qml b/src/gui/EncryptionTokenSelectionWindow.qml index 95256e7d3d37d..6e3379badbe23 100644 --- a/src/gui/EncryptionTokenSelectionWindow.qml +++ b/src/gui/EncryptionTokenSelectionWindow.qml @@ -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 @@ -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 } } } @@ -126,10 +128,12 @@ ApplicationWindow { onAccepted: function() { Systray.destroyDialog(encryptionKeyChooserDialog) + certificateSelector.serialNumber = selectedSerialNumber } onRejected: function() { Systray.destroyDialog(encryptionKeyChooserDialog) + certificateSelector.serialNumber = '' } } } diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp index 7e11fecb35be0..62efbdfe70dce 100644 --- a/src/gui/accountsettings.cpp +++ b/src/gui/accountsettings.cpp @@ -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(); @@ -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; @@ -1640,7 +1630,7 @@ void AccountSettings::initializeE2eEncryption() } }); _accountState->account()->setE2eEncryptionKeysGenerationAllowed(false); - _accountState->account()->e2e()->initialize(_accountState->account()); + _accountState->account()->e2e()->initialize(this, _accountState->account()); } } diff --git a/src/gui/accountsettings.h b/src/gui/accountsettings.h index b24b48e6236b3..64908a10294c0 100644 --- a/src/gui/accountsettings.h +++ b/src/gui/accountsettings.h @@ -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, diff --git a/src/gui/connectionvalidator.cpp b/src/gui/connectionvalidator.cpp index f9b149787ed01..8b10f58f90f98 100644 --- a/src/gui/connectionvalidator.cpp +++ b/src/gui/connectionvalidator.cpp @@ -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 diff --git a/src/gui/owncloudgui.cpp b/src/gui/owncloudgui.cpp index 1871b9c7d4ebf..e6cdbfa845692 100644 --- a/src/gui/owncloudgui.cpp +++ b/src/gui/owncloudgui.cpp @@ -132,6 +132,7 @@ ownCloudGui::ownCloudGui(Application *parent) qmlRegisterUncreatableType("com.nextcloud.desktopclient", 1, 0, "UnifiedSearchResultsListModel", "UnifiedSearchResultsListModel"); qmlRegisterUncreatableType("com.nextcloud.desktopclient", 1, 0, "UserStatus", "Access to Status enum"); qmlRegisterUncreatableType("com.nextcloud.desktopclient", 1, 0, "Sharee", "Access to Type enum"); + qmlRegisterUncreatableType("com.nextcloud.desktopclient", 1, 0, "ClientSideTokenSelector", "Access to the certificate selector"); qRegisterMetaTypeStreamOperators(); diff --git a/src/gui/systray.cpp b/src/gui/systray.cpp index 4a32eaefd8b03..e146da5161ef3 100644 --- a/src/gui/systray.cpp +++ b/src/gui/systray.cpp @@ -24,6 +24,7 @@ #include "configfile.h" #include "accessmanager.h" #include "callstatechecker.h" +#include "clientsidetokenselector.h" #include #include @@ -35,6 +36,7 @@ #include #include #include +#include #ifdef USE_FDO_NOTIFICATIONS #include @@ -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(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); diff --git a/src/gui/systray.h b/src/gui/systray.h index d0789bc47be3d..0c019edae936b 100644 --- a/src/gui/systray.h +++ b/src/gui/systray.h @@ -31,6 +31,8 @@ class QGuiApplication; namespace OCC { +class ClientSideTokenSelector; + class AccessManagerFactory : public QQmlNetworkAccessManagerFactory { public: @@ -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); diff --git a/src/libsync/clientsideencryption.cpp b/src/libsync/clientsideencryption.cpp index 28caaa88791f7..2cdb2a473be7b 100644 --- a/src/libsync/clientsideencryption.cpp +++ b/src/libsync/clientsideencryption.cpp @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include #include #include @@ -1014,23 +1016,13 @@ std::optional 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 @@ -1083,7 +1075,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); @@ -1096,11 +1094,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(); } @@ -1112,7 +1110,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(); @@ -1156,27 +1155,46 @@ void ClientSideEncryption::initializeHardwareTokenEncryption(const AccountPtr &a return; } - /* perform pkcs #11 login */ - QByteArray password = "0000"; - if (PKCS11_login(slot, 0, password.data()) != 0) { - qCWarning(lcCse()) << "PKCS11_login failed" << ERR_reason_error_string(ERR_get_error()); + while (true) { + /* perform pkcs #11 login */ + bool ok; + QString text = QInputDialog::getText(settingsDialog, + tr("PIN needed to login to token"), + tr("PIN:"), + QLineEdit::Password, + {}, + &ok); + if (!ok || text.isEmpty()) { + qCWarning(lcCse()) << "an USER pin is required"; - failedToInitialize(account); - return; - } + failedToInitialize(account); + return; + } - /* check if user is logged in */ - if (PKCS11_is_logged_in(slot, 0, &logged_in) != 0) { - qCWarning(lcCse()) << "PKCS11_is_logged_in failed" << ERR_reason_error_string(ERR_get_error()); + const auto password = text.toLatin1(); + if (PKCS11_login(slot, 0, password.data()) != 0) { + QMessageBox::warning(settingsDialog, + tr("Invalid PIN. Login failed"), + tr("Login to the token failed after providing the user PIN. It may be invalid or wrong. Please try again !"), + QMessageBox::Ok); + continue; + } - failedToInitialize(account); - return; - } - if (!logged_in) { - qCWarning(lcCse()) << "PKCS11_is_logged_in says user is not logged in, expected to be logged in"; + /* check if user is logged in */ + if (PKCS11_is_logged_in(slot, 0, &logged_in) != 0) { + qCWarning(lcCse()) << "PKCS11_is_logged_in failed" << ERR_reason_error_string(ERR_get_error()); - failedToInitialize(account); - return; + failedToInitialize(account); + return; + } + if (!logged_in) { + qCWarning(lcCse()) << "PKCS11_is_logged_in says user is not logged in, expected to be logged in"; + + failedToInitialize(account); + return; + } + + break; } auto privateKeysCount = 0u; @@ -1518,6 +1536,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(); + 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); diff --git a/src/libsync/clientsideencryption.h b/src/libsync/clientsideencryption.h index 8078e3171c25c..9bfcd4dfc8ffb 100644 --- a/src/libsync/clientsideencryption.h +++ b/src/libsync/clientsideencryption.h @@ -36,6 +36,8 @@ #include +class QWidget; + namespace QKeychain { class Job; class WritePasswordJob; @@ -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); @@ -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); @@ -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: @@ -206,6 +207,8 @@ private slots: void writePrivateKey(const OCC::AccountPtr &account); void writeCertificate(const OCC::AccountPtr &account); + void completeHardwareTokenInitialization(); + private: void generateMnemonic(); diff --git a/src/libsync/clientsidetokenselector.cpp b/src/libsync/clientsidetokenselector.cpp index 6bb8d0857f9b3..d3f4781bda8c8 100644 --- a/src/libsync/clientsidetokenselector.cpp +++ b/src/libsync/clientsidetokenselector.cpp @@ -12,6 +12,7 @@ * for more details. */ +#include #define OPENSSL_SUPPRESS_DEPRECATED #include "clientsidetokenselector.h" @@ -22,58 +23,82 @@ #include -namespace OCC -{ +namespace { -Q_LOGGING_CATEGORY(lcCseSelector, "nextcloud.sync.clientsideencryption.selector", QtInfoMsg) +class Bio { +public: + Bio() + : _bio(BIO_new(BIO_s_mem())) + { + } -ClientSideTokenSelector::ClientSideTokenSelector(QObject *parent) - : QObject{parent} -{ + ~Bio() + { + BIO_free_all(_bio); + } -} + operator const BIO*() const + { + return _bio; + } -bool ClientSideTokenSelector::isSetup() const + operator BIO*() + { + return _bio; + } + +private: + Q_DISABLE_COPY(Bio) + + BIO* _bio; +}; + +static unsigned char* unsignedData(QByteArray& array) { - return false; + return (unsigned char*)array.data(); } -QVariantList ClientSideTokenSelector::discoveredTokens() const -{ - return _discoveredTokens; +static QByteArray BIO2ByteArray(Bio &b) { + auto pending = static_cast(BIO_ctrl_pending(b)); + QByteArray res(pending, '\0'); + BIO_read(b, unsignedData(res), pending); + return res; } -QVariantList ClientSideTokenSelector::discoveredKeys() const -{ - return _discoveredPrivateKeys; } -QString ClientSideTokenSelector::slotManufacturer() const +namespace OCC { - return _slotManufacturer; + +Q_LOGGING_CATEGORY(lcCseSelector, "nextcloud.sync.clientsideencryption.selector", QtInfoMsg) + +ClientSideTokenSelector::ClientSideTokenSelector(QObject *parent) + : QObject{parent} +{ + } -QString ClientSideTokenSelector::tokenManufacturer() const +bool ClientSideTokenSelector::isSetup() const { - return _tokenManufacturer; + return !_issuer.isEmpty() && !_serialNumber.isEmpty(); } -QString ClientSideTokenSelector::tokenModel() const +QVariantList ClientSideTokenSelector::discoveredCertificates() const { - return _tokenModel; + return _discoveredCertificates; } -QString ClientSideTokenSelector::tokenSerialNumber() const +QString ClientSideTokenSelector::serialNumber() const { - return _tokenSerialNumber; + return _serialNumber; } -int ClientSideTokenSelector::keyIndex() const +QString ClientSideTokenSelector::issuer() const { - return _keyIndex; + return _issuer; } -void ClientSideTokenSelector::searchForToken(const AccountPtr &account) +void ClientSideTokenSelector::searchForCertificates(const AccountPtr &account) { auto ctx = PKCS11_CTX_new(); @@ -95,8 +120,7 @@ void ClientSideTokenSelector::searchForToken(const AccountPtr &account) return; } - _discoveredTokens.clear(); - _discoveredPrivateKeys.clear(); + _discoveredCertificates.clear(); auto currentSlot = static_cast(nullptr); for(auto i = 0u; i < tokensCount; ++i) { currentSlot = PKCS11_find_next_token(ctx, tokenSlots, tokensCount, currentSlot); @@ -104,96 +128,118 @@ void ClientSideTokenSelector::searchForToken(const AccountPtr &account) break; } - 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("slotManufacturer"), QString::fromLatin1(currentSlot->manufacturer)}, - {QStringLiteral("slotDescription"), QString::fromLatin1(currentSlot->description)}, - {QStringLiteral("tokenLabel"), QString::fromLatin1(currentSlot->token->label)}, - {QStringLiteral("tokenManufacturer"), QString::fromLatin1(currentSlot->token->manufacturer)}, - {QStringLiteral("tokenModel"), QString::fromLatin1(currentSlot->token->model)}, - {QStringLiteral("tokenSerialNumber"), QString::fromLatin1(currentSlot->token->serialnr)}, - }); + qCDebug(lcCseSelector()) << "Slot manufacturer......:" << currentSlot->manufacturer; + qCDebug(lcCseSelector()) << "Slot description.......:" << currentSlot->description; + qCDebug(lcCseSelector()) << "Slot token label.......:" << currentSlot->token->label; + qCDebug(lcCseSelector()) << "Slot token manufacturer:" << currentSlot->token->manufacturer; + qCDebug(lcCseSelector()) << "Slot token model.......:" << currentSlot->token->model; + qCDebug(lcCseSelector()) << "Slot token serialnr....:" << currentSlot->token->serialnr; auto keysCount = 0u; - auto tokenKeys = static_cast(nullptr); - if (PKCS11_enumerate_public_keys(currentSlot->token, &tokenKeys, &keysCount)) { - qCWarning(lcCseSelector()) << "PKCS11_enumerate_public_keys failed" << ERR_reason_error_string(ERR_get_error()); + auto certificatesFromToken = static_cast(nullptr); + if (PKCS11_enumerate_certs(currentSlot->token, &certificatesFromToken, &keysCount)) { + qCWarning(lcCseSelector()) << "PKCS11_enumerate_certs failed" << ERR_reason_error_string(ERR_get_error()); Q_EMIT failedToInitialize(account); return; } - for (auto keyIndex = 0u; keyIndex < keysCount; ++keyIndex) { - auto currentPrivateKey = &tokenKeys[0]; - qCInfo(lcCseSelector()) << "key metadata:" - << "type:" << (currentPrivateKey->isPrivate ? "is private" : "is public") - << "label:" << currentPrivateKey->label - << "need login:" << (currentPrivateKey->needLogin ? "true" : "false"); - - _discoveredPrivateKeys.push_back(QVariantMap{ - {QStringLiteral("label"), QString::fromLatin1(currentPrivateKey->label)}, - {QStringLiteral("needLogin"), QVariant::fromValue(currentPrivateKey->needLogin)}, - }); + for (auto certificateIndex = 0u; certificateIndex < keysCount; ++certificateIndex) { + const auto currentCertificate = &certificatesFromToken[certificateIndex]; + qCInfo(lcCseSelector()) << "certificate metadata:" + << "label:" << currentCertificate->label; + + const auto certificateId = QByteArray{reinterpret_cast(currentCertificate->id), static_cast(currentCertificate->id_len)}; + qCInfo(lcCseSelector()) << "new certificate ID:" << certificateId.toBase64(); + + const auto certificateSubjectName = X509_get_subject_name(currentCertificate->x509); + if (!certificateSubjectName) { + qCWarning(lcCseSelector()) << "X509_get_subject_name failed" << ERR_reason_error_string(ERR_get_error()); + + Q_EMIT failedToInitialize(account); + return; + } + + Bio out; + const auto ret = PEM_write_bio_X509(out, currentCertificate->x509); + if (ret <= 0){ + qCWarning(lcCseSelector()) << "PEM_write_bio_X509 failed" << ERR_reason_error_string(ERR_get_error()); + + Q_EMIT failedToInitialize(account); + return; + } + + const auto result = BIO2ByteArray(out); + const auto sslCertificate = QSslCertificate{result, QSsl::Pem}; + + qCInfo(lcCseSelector()) << "newly found certificate" + << "subject:" << sslCertificate.subjectDisplayName() + << "issuer:" << sslCertificate.issuerDisplayName() + << "valid since:" << sslCertificate.effectiveDate() + << "valid until:" << sslCertificate.expiryDate() + << "serial number:" << sslCertificate.serialNumber(); + + if (sslCertificate.isSelfSigned()) { + qCInfo(lcCseSelector()) << "newly found certificate is self signed: goint to ignore it"; + continue; + } + + _discoveredCertificates.push_back(QVariantMap{ + {QStringLiteral("label"), QString::fromLatin1(currentCertificate->label)}, + {QStringLiteral("subject"), sslCertificate.subjectDisplayName()}, + {QStringLiteral("issuer"), sslCertificate.issuerDisplayName()}, + {QStringLiteral("serialNumber"), sslCertificate.serialNumber()}, + {QStringLiteral("validSince"), sslCertificate.effectiveDate()}, + {QStringLiteral("validUntil"), sslCertificate.expiryDate()}, + {QStringLiteral("certificate"), QVariant::fromValue(sslCertificate)}, + }); } } - Q_EMIT discoveredTokensChanged(); - Q_EMIT discoveredKeysChanged(); -} -void ClientSideTokenSelector::setSlotManufacturer(const QString &slotManufacturer) -{ - if (_slotManufacturer == slotManufacturer) { - return; - } - - _slotManufacturer = slotManufacturer; - Q_EMIT slotManufacturerChanged(); + Q_EMIT discoveredCertificatesChanged(); + processDiscoveredCertificates(); } -void ClientSideTokenSelector::setTokenManufacturer(const QString &tokenManufacturer) +void ClientSideTokenSelector::setSerialNumber(const QString &serialNumber) { - if (_tokenManufacturer == tokenManufacturer) { + if (_serialNumber == serialNumber) { return; } - _tokenManufacturer = tokenManufacturer; - Q_EMIT tokenManufacturerChanged(); + _serialNumber = serialNumber; + Q_EMIT serialNumberChanged(); } -void ClientSideTokenSelector::setTokenModel(const QString &tokenModel) +void ClientSideTokenSelector::setIssuer(const QString &issuer) { - if (_tokenModel == tokenModel) { + if (_issuer == issuer) { return; } - _tokenModel = tokenModel; - Q_EMIT tokenModelChanged(); + _issuer = issuer; + Q_EMIT issuerChanged(); } -void ClientSideTokenSelector::setTokenSerialNumber(const QString &tokenSerialNumber) +void ClientSideTokenSelector::processDiscoveredCertificates() { - if (_tokenSerialNumber == tokenSerialNumber) { - return; - } - - _tokenSerialNumber = tokenSerialNumber; - Q_EMIT tokenSerialNumberChanged(); -} + for (const auto &oneCertificate : discoveredCertificates()) { + const auto certificateData = oneCertificate.toMap(); + const auto sslCertificate = certificateData[QStringLiteral("certificate")].value(); + if (sslCertificate.isNull()) { + qCDebug(lcCseSelector()) << "null certificate"; + continue; + } + const auto sslErrors = QSslCertificate::verify({sslCertificate}); + for (const auto &oneError : sslErrors) { + qCInfo(lcCseSelector()) << oneError; + } + qCInfo(lcCseSelector()) << "certificate is valid" << certificateData[QStringLiteral("serialNumber")] << certificateData[QStringLiteral("issuer")]; -void ClientSideTokenSelector::setKeyIndex(int keyIndex) -{ - if (_keyIndex == keyIndex) { + setIssuer(certificateData[QStringLiteral("issuer")].toString()); + setSerialNumber(certificateData[QStringLiteral("serialNumber")].toString()); + Q_EMIT isSetupChanged(); return; } - - _keyIndex = keyIndex; - Q_EMIT keyIndexChanged(); } } diff --git a/src/libsync/clientsidetokenselector.h b/src/libsync/clientsidetokenselector.h index a5f76db4b81fd..72df55fb46b92 100644 --- a/src/libsync/clientsidetokenselector.h +++ b/src/libsync/clientsidetokenselector.h @@ -16,100 +16,66 @@ #define CLIENTSIDETOKENSELECTOR_H #include "accountfwd.h" +#include "owncloudlib.h" #include namespace OCC { -class ClientSideTokenSelector : public QObject +class OWNCLOUDSYNC_EXPORT ClientSideTokenSelector : public QObject { Q_OBJECT Q_PROPERTY(bool isSetup READ isSetup NOTIFY isSetupChanged) - Q_PROPERTY(QVariantList discoveredTokens READ discoveredTokens NOTIFY discoveredTokensChanged) + Q_PROPERTY(QVariantList discoveredCertificates READ discoveredCertificates NOTIFY discoveredCertificatesChanged) - Q_PROPERTY(QVariantList discoveredKeys READ discoveredKeys NOTIFY discoveredKeysChanged) + Q_PROPERTY(QString serialNumber READ serialNumber NOTIFY serialNumberChanged) - Q_PROPERTY(QString slotManufacturer READ slotManufacturer WRITE setSlotManufacturer NOTIFY slotManufacturerChanged) - - Q_PROPERTY(QString tokenManufacturer READ tokenManufacturer WRITE setTokenManufacturer NOTIFY tokenManufacturerChanged) - - Q_PROPERTY(QString tokenModel READ tokenModel WRITE setTokenModel NOTIFY tokenModelChanged) - - Q_PROPERTY(QString tokenSerialNumber READ tokenSerialNumber WRITE setTokenSerialNumber NOTIFY tokenSerialNumberChanged) - - Q_PROPERTY(int keyIndex READ keyIndex WRITE setKeyIndex NOTIFY keyIndexChanged) + Q_PROPERTY(QString issuer READ issuer NOTIFY issuerChanged) public: explicit ClientSideTokenSelector(QObject *parent = nullptr); [[nodiscard]] bool isSetup() const; - [[nodiscard]] QVariantList discoveredTokens() const; - - [[nodiscard]] QVariantList discoveredKeys() const; + [[nodiscard]] QVariantList discoveredCertificates() const; - [[nodiscard]] QString slotManufacturer() const; + [[nodiscard]] QString serialNumber() const; - [[nodiscard]] QString tokenManufacturer() const; - - [[nodiscard]] QString tokenModel() const; - - [[nodiscard]] QString tokenSerialNumber() const; - - [[nodiscard]] int keyIndex() const; + [[nodiscard]] QString issuer() const; public slots: + void searchForCertificates(const OCC::AccountPtr &account); - void searchForToken(const OCC::AccountPtr &account); - - void setSlotManufacturer(const QString &slotManufacturer); - - void setTokenManufacturer(const QString &tokenManufacturer); +private slots: + void setSerialNumber(const QString &serialNumber); - void setTokenModel(const QString &tokenModel); - - void setTokenSerialNumber(const QString &tokenSerialNumber); - - void setKeyIndex(int keyIndex); + void setIssuer(const QString &issuer); signals: void isSetupChanged(); - void discoveredTokensChanged(); - - void discoveredKeysChanged(); - - void slotManufacturerChanged(); - - void tokenManufacturerChanged(); + void discoveredCertificatesChanged(); - void tokenModelChanged(); + void certificateIndexChanged(); - void tokenSerialNumberChanged(); + void serialNumberChanged(); - void keyIndexChanged(); + void issuerChanged(); void failedToInitialize(const OCC::AccountPtr &account); private: + void processDiscoveredCertificates(); - QVariantList _discoveredTokens; - - QVariantList _discoveredPrivateKeys; - - QString _slotManufacturer; - - QString _tokenManufacturer; - - QString _tokenModel; + QVariantList _discoveredCertificates; - QString _tokenSerialNumber; + QString _serialNumber; - int _keyIndex = -1; + QString _issuer; }; }