Skip to content
Open
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
8 changes: 8 additions & 0 deletions client/CDocSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,14 @@ DDConfiguration::shareServersKnown(const std::string &shareUrls)
!shareServer(QLatin1String("CDOC2-SHARES-RP"), QLatin1String("RP"), shareUrls).empty();
}

std::string
DDConfiguration::defaultShareServer()
{
QString id = Settings::CDOC2_DEFAULT_KEYSERVER;
QJsonObject data = Application::confValue(QLatin1String("CDOC2-CONF")).toObject().value(id).toObject();
return data.value(QLatin1String("SHARES")).toArray().size() >= 2 ? id.toStdString() : std::string();
}

std::string
DDConfiguration::getValue(std::string_view domain, std::string_view param) const
{
Expand Down
3 changes: 3 additions & 0 deletions client/CDocSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ struct DDConfiguration : public libcdoc::Configuration {
// Whether the authentication and relying party servers for a lock's share
// servers (Lock::SHARE_URLS) are configured, i.e. Mobile-ID / Smart-ID can open it
static bool shareServersKnown(const std::string &shareUrls);
// The default key server's CDOC2-CONF entry, when it lists the two key share
// servers libcdoc needs to encrypt for Mobile-ID / Smart-ID; empty otherwise
static std::string defaultShareServer();
// Mobile-ID / Smart-ID decryption: Configuration::SHARE_SIGNER_MID or
// SHARE_SIGNER_SID, the Mobile-ID phone number, and the lock's share servers
// (Lock::SHARE_URLS) that select the CDOC2-CONF entry
Expand Down
32 changes: 32 additions & 0 deletions client/CryptoDoc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ CKey::CKey(QSslCertificate _rcpt_cert) : lock(libcdoc::Lock::PUBLIC_KEY), rcpt_c
lock.setBytes(libcdoc::Lock::CERT, std::vector<uint8_t>(der.cbegin(), der.cend()));
}

CKey
CKey::share(const QString &personalCode)
{
libcdoc::Lock lock(libcdoc::Lock::SHARE_SERVER);
// The form CDoc2 stores it in, so a new recipient reads the same as an encrypted one
lock.setString(libcdoc::Lock::RECIPIENT_ID, "etsi/PNOEE-" + personalCode.toStdString());
return CKey(lock);
}

bool
CKey::canDecrypt(const QSslCertificate &cert) const
{
Expand Down Expand Up @@ -94,6 +103,8 @@ CKey::isSupported() const
bool
CKey::operator==(const CKey& rhs) const
{
if (lock.type == libcdoc::Lock::SHARE_SERVER && rhs.lock.type == libcdoc::Lock::SHARE_SERVER)
return lock.getString(libcdoc::Lock::RECIPIENT_ID) == rhs.lock.getString(libcdoc::Lock::RECIPIENT_ID);
if (!lock.isPKI() || !rhs.lock.isPKI()) return false;
return lock.getBytes(libcdoc::Lock::RCPT_KEY) == rhs.lock.getBytes(libcdoc::Lock::RCPT_KEY);
}
Expand Down Expand Up @@ -265,6 +276,12 @@ CryptoDoc::supportsSymmetricKeys() const
return !d->reader && (d->version == 2);
}

bool
CryptoDoc::supportsKeyShares() const
{
return supportsSymmetricKeys() && !DDConfiguration::defaultShareServer().empty();
}

bool CryptoDoc::addEncryptionKey(const CKey& key) {
if(d->isEncryptedWarning(tr("Failed to add key")))
return false;
Expand Down Expand Up @@ -489,6 +506,16 @@ bool CryptoDoc::encrypt(const QString &filename, const QString& label, const QBy
->open();
return false;
}
const std::string share_server = DDConfiguration::defaultShareServer();
if(std::ranges::any_of(d->keys, [](const CKey &key) { return key.lock.type == libcdoc::Lock::SHARE_SERVER; }) &&
(d->version != 2 || share_server.empty()))
{
WarningDialog::create()
->withTitle(tr("Failed to encrypt document"))
->withText(tr("Key share servers for Mobile-ID and Smart-ID are not configured"))
->open();
return false;
}
QString writer_last_error;
auto keepAlive = FileDialog::keepAccessAlive(d->fileName);
libcdoc::result_t result = waitFor([&] -> libcdoc::result_t {
Expand All @@ -514,6 +541,11 @@ bool CryptoDoc::encrypt(const QString &filename, const QString& label, const QBy
case libcdoc::Lock::SERVER:
enc_keys.push_back(libcdoc::Recipient::makePublicKey(key.lock, keyserver_id));
break;
case libcdoc::Lock::SHARE_SERVER:
// "etsi/PNOEE-..." -> "PNOEE-...", libcdoc adds the prefix back
enc_keys.push_back(libcdoc::Recipient::makeShare({}, share_server,
key.lock.getString(libcdoc::Lock::RECIPIENT_ID).substr(5)));
break;
default:
break;
}
Expand Down
3 changes: 3 additions & 0 deletions client/CryptoDoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ struct CKey {
public:
CKey(const libcdoc::Lock& _lock) : lock(_lock) {}
CKey(QSslCertificate rcpt_cert);
// Mobile-ID / Smart-ID recipient, encrypted for through key share servers
static CKey share(const QString &personalCode);

libcdoc::Lock lock;
QSslCertificate rcpt_cert;
Expand All @@ -63,6 +65,7 @@ class CryptoDoc final: public QObject
~CryptoDoc() final;

bool supportsSymmetricKeys() const;
bool supportsKeyShares() const;
bool addEncryptionKey(const CKey& key);
void clear(const QString &file = {}, int version = -1);
bool decrypt(const libcdoc::Lock &lock, const QByteArray& secret, std::unique_ptr<QCryptoBackend> &&backend);
Expand Down
15 changes: 12 additions & 3 deletions client/dialogs/AddRecipients.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ struct AddRecipients::Private: public Ui::AddRecipients
QPushButton *btnFind;
};

AddRecipients::AddRecipients(ItemList* itemList, QWidget *parent)
AddRecipients::AddRecipients(ItemList* itemList, bool keyShares, QWidget *parent)
: QDialog(parent)
, ui(new Private)
, keyShares(keyShares)
{
#ifndef Q_OS_WIN
if(const auto list = Application::confValue(QLatin1String("LDAP-CERTS")).toArray();
Expand Down Expand Up @@ -235,7 +236,11 @@ void AddRecipients::addRecipientFromHistory()

void AddRecipients::addRecipient(const QSslCertificate& cert, bool select)
{
CKey key(cert);
addRecipient(CKey(cert), select);
}

void AddRecipients::addRecipient(const CKey &key, bool select)
{
AddressItem *leftItem = itemListValue(ui->leftPane, key);
if(!leftItem)
{
Expand All @@ -257,7 +262,8 @@ void AddRecipients::addRecipientToRightPane(Item *item, bool update)
const CKey& key = address->getKey();
if (rightList.contains(key)) return;

if(update)
// A Mobile-ID / Smart-ID recipient has no certificate to check
if(update && !key.rcpt_cert.isNull())
{
if(auto expiryDate = key.rcpt_cert.expiryDate(); expiryDate <= QDateTime::currentDateTime())
{
Expand Down Expand Up @@ -367,6 +373,9 @@ void AddRecipients::search(const QString &term, bool select, const QString &type
ldap_corp->search(QStringLiteral("(serialNumber=%1)" ).arg(cleanTerm), userData);
else if(IKValidator::isValid(cleanTerm))
{
// Mobile-ID / Smart-ID certificates are not in LDAP; any person can be offered it
if(keyShares)
addRecipient(CKey::share(cleanTerm), false);
userData[QStringLiteral("personSearch")] = true;
for(auto *ldap: ldap_person) {
ldap->search(QStringLiteral("(serialNumber=PNOEE-%1)").arg(cleanTerm), userData);
Expand Down
5 changes: 4 additions & 1 deletion client/dialogs/AddRecipients.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ class AddRecipients final : public QDialog
Q_OBJECT

public:
explicit AddRecipients(ItemList* itemList, QWidget *parent = nullptr);
// keyShares offers Mobile-ID / Smart-ID for a searched personal code
explicit AddRecipients(ItemList* itemList, bool keyShares, QWidget *parent = nullptr);
~AddRecipients() final;

QList<CKey> keys() const;
Expand All @@ -50,6 +51,7 @@ class AddRecipients final : public QDialog
void addRecipientFromFile();
void addRecipientFromHistory();
void addRecipient(const QSslCertificate& cert, bool select = true);
void addRecipient(const CKey &key, bool select);
void addRecipientToRightPane(Item *item, bool update = true);

static AddressItem* itemListValue(ItemList *list, const CKey &key);
Expand All @@ -63,6 +65,7 @@ class AddRecipients final : public QDialog
QList<LdapSearch*> ldap_person;
LdapSearch *ldap_corp;
int multiSearch = 0;
const bool keyShares;

QTemporaryFile ldapCACerts;
HistoryList historyCertData;
Expand Down
4 changes: 4 additions & 0 deletions client/translations/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,10 @@
<source>Key transfer server is not configured</source>
<translation>Key transfer server is not configured</translation>
</message>
<message>
<source>Key share servers for Mobile-ID and Smart-ID are not configured</source>
<translation>Key share servers for Mobile-ID and Smart-ID are not configured</translation>
</message>
<message>
<source>Failed to remove key</source>
<translation>Failed to remove key</translation>
Expand Down
4 changes: 4 additions & 0 deletions client/translations/et.ts
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,10 @@
<source>Key transfer server is not configured</source>
<translation>Võtmeedastusserver ei ole seadistatud</translation>
</message>
<message>
<source>Key share servers for Mobile-ID and Smart-ID are not configured</source>
<translation>Mobiil-ID ja Smart-ID võtmeosade servereid ei ole seadistatud</translation>
</message>
<message>
<source>Failed to remove key</source>
<translation>Võtme eemaldamine ebaõnnestus</translation>
Expand Down
2 changes: 1 addition & 1 deletion client/widgets/ContainerPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ void ContainerPage::transition(CryptoDoc *container)
});
disconnect(ui->rightPane, &ItemList::add, container, nullptr);
connect(ui->rightPane, &ItemList::add, container, [this, container] {
AddRecipients dlg(ui->rightPane, this);
AddRecipients dlg(ui->rightPane, container->supportsKeyShares(), this);
if(!dlg.exec() || !dlg.isUpdated())
return;
container->clearKeys();
Expand Down
Loading