Page MenuHome GnuPG

No OneTemporary

diff --git a/src/kleo/keyresolver.cpp b/src/kleo/keyresolver.cpp
index 19a8d3cf..19611f6c 100644
--- a/src/kleo/keyresolver.cpp
+++ b/src/kleo/keyresolver.cpp
@@ -1,693 +1,592 @@
/* -*- c++ -*-
keyresolver.cpp
This file is part of libkleopatra, the KDE keymanagement library
SPDX-FileCopyrightText: 2004 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2018 Intevation GmbH
Based on kpgp.cpp
SPDX-FileCopyrightText: 2001, 2002 the KPGP authors
See file libkdenetwork/AUTHORS.kpgp for details
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "keyresolver.h"
#include "models/keycache.h"
#include "ui/newkeyapprovaldialog.h"
#include "utils/formatting.h"
#include <gpgme++/key.h>
#include "libkleo_debug.h"
using namespace Kleo;
+using namespace GpgME;
namespace {
-static inline bool ValidEncryptionKey(const GpgME::Key &key)
+static inline bool ValidEncryptionKey(const Key &key)
{
if (key.isNull() || key.isRevoked() || key.isExpired() ||
key.isDisabled() || !key.canEncrypt()) {
return false;
}
return true;
}
-static inline bool ValidSigningKey(const GpgME::Key &key)
+static inline bool ValidSigningKey(const Key &key)
{
if (key.isNull() || key.isRevoked() || key.isExpired() ||
key.isDisabled() || !key.canSign() || !key.hasSecret()) {
return false;
}
return true;
}
} // namespace
class KeyResolver::Private
{
public:
- Private(KeyResolver* qq, bool enc, bool sig, CryptoMessageFormat fmt, bool allowMixed) :
+ Private(KeyResolver* qq, bool enc, bool sig, Protocol fmt, bool allowMixed) :
q(qq), mFormat(fmt), mEncrypt(enc), mSign(sig),
mAllowMixed(allowMixed),
mCache(KeyCache::instance()),
mDialogWindowFlags(Qt::WindowFlags()),
- mPreferredProtocol(GpgME::UnknownProtocol),
- mMinimumValidity(GpgME::UserID::Marginal),
+ mPreferredProtocol(UnknownProtocol),
+ mMinimumValidity(UserID::Marginal),
mCompliance(Formatting::complianceMode())
{
}
~Private() = default;
- bool isAcceptableSigningKey(const GpgME::Key &key)
+ bool isAcceptableSigningKey(const Key &key)
{
if (!ValidSigningKey(key)) {
return false;
}
if (mCompliance == QLatin1String("de-vs")) {
if (!Formatting::isKeyDeVs(key)) {
qCDebug(LIBKLEO_LOG) << "Rejected sig key" << key.primaryFingerprint()
<< "because it is not de-vs compliant.";
return false;
}
}
return true;
}
- bool isAcceptableEncryptionKey(const GpgME::Key &key, const QString &address = QString())
+ bool isAcceptableEncryptionKey(const Key &key, const QString &address = QString())
{
if (!ValidEncryptionKey(key)) {
return false;
}
if (mCompliance == QLatin1String("de-vs")) {
if (!Formatting::isKeyDeVs(key)) {
qCDebug(LIBKLEO_LOG) << "Rejected enc key" << key.primaryFingerprint()
<< "because it is not de-vs compliant.";
return false;
}
}
if (address.isEmpty()) {
return true;
}
for (const auto &uid: key.userIDs()) {
if (uid.addrSpec() == address.toStdString()) {
if (uid.validity() >= mMinimumValidity) {
return true;
}
}
}
return false;
}
void addRecpients (const QStringList &addresses)
{
if (!mEncrypt) {
return;
}
// Internally we work with normalized addresses. Normalization
// matches the gnupg one.
for (const auto &addr :addresses) {
// PGP Uids are defined to be UTF-8 (RFC 4880 §5.11)
- const auto normalized = GpgME::UserID::addrSpecFromString (addr.toUtf8().constData());
+ const auto normalized = UserID::addrSpecFromString (addr.toUtf8().constData());
if (normalized.empty()) {
// should not happen bug in the caller, non localized
// error for bug reporting.
mFatalErrors << QStringLiteral("The mail address for '%1' could not be extracted").arg(addr);
continue;
}
const QString normStr = QString::fromUtf8(normalized.c_str());
// Initially mark them as unresolved for both protocols
if (!mUnresolvedCMS.contains(normStr)) {
mUnresolvedCMS << normStr;
}
if (!mUnresolvedPGP.contains(normStr)) {
mUnresolvedPGP << normStr;
}
mRecipients << normStr;
}
}
// Apply the overrides this is also where specific formats come in
void resolveOverrides()
{
if (!mEncrypt) {
// No encryption we are done.
return;
}
- for (CryptoMessageFormat fmt: mOverrides.keys()) {
+ for (Protocol fmt: mOverrides.keys()) {
// Iterate over the crypto message formats
- if (mFormat != AutoFormat && mFormat != fmt && fmt != AutoFormat) {
+ if (mFormat != UnknownProtocol && mFormat != fmt && fmt != UnknownProtocol) {
// Skip overrides for the wrong format
continue;
}
for (const auto &addr: mOverrides[fmt].keys()) {
// For all address overrides of this format.
for (const auto &fprOrId: mOverrides[fmt][addr]) {
// For all the keys configured for this address.
const auto key = mCache->findByKeyIDOrFingerprint(fprOrId.toUtf8().constData());
if (key.isNull()) {
qCDebug (LIBKLEO_LOG) << "Failed to find override key for:" << addr
<< "fpr:" << fprOrId;
continue;
}
// Now add it to the resolved keys and remove it from our list
// of unresolved keys.
if (!mRecipients.contains(addr)) {
qCDebug(LIBKLEO_LOG) << "Override provided for an address that is "
"neither sender nor recipient. Address: " << addr;
continue;
}
- CryptoMessageFormat resolvedFmt = fmt;
- if (fmt == AutoFormat) {
+ Protocol resolvedFmt = fmt;
+ if (fmt == UnknownProtocol) {
// Take the format from the key.
- if (key.protocol() == GpgME::OpenPGP) {
- resolvedFmt = AnyOpenPGP;
- } else {
- resolvedFmt = AnySMIME;
- }
+ resolvedFmt = key.protocol();
}
auto recpMap = mEncKeys.value(resolvedFmt);
auto keys = recpMap.value(addr);
keys.push_back(key);
recpMap.insert(addr, keys);
mEncKeys.insert(resolvedFmt, recpMap);
// Now we can remove it from our unresolved lists.
- if (key.protocol() == GpgME::OpenPGP) {
+ if (key.protocol() == OpenPGP) {
mUnresolvedPGP.removeAll(addr);
} else {
mUnresolvedCMS.removeAll(addr);
}
- qCDebug(LIBKLEO_LOG) << "Override" << addr << cryptoMessageFormatToString (resolvedFmt) << fprOrId;
+ qCDebug(LIBKLEO_LOG) << "Override" << addr << Formatting::displayName(resolvedFmt) << fprOrId;
}
}
}
}
- void resolveSign(GpgME::Protocol proto)
+ void resolveSign(Protocol proto)
{
- auto fmt = proto == GpgME::OpenPGP ? AnyOpenPGP : AnySMIME;
- if (mSigKeys.contains(fmt)) {
+ if (mSigKeys.contains(proto)) {
// Explicitly set
return;
}
const auto keys = mCache->findBestByMailBox(mSender.toUtf8().constData(),
proto, true, false);
for (const auto &key: keys) {
if (key.isNull()) {
continue;
}
if (!isAcceptableSigningKey(key)) {
qCDebug(LIBKLEO_LOG) << "Unacceptable signing key" << key.primaryFingerprint()
<< "for" << mSender;
return;
}
}
if (!keys.empty() && !keys[0].isNull()) {
- mSigKeys.insert(fmt, keys);
+ mSigKeys.insert(proto, keys);
}
}
- void setSigningKeys(const std::vector<GpgME::Key> &keys)
+ void setSigningKeys(const std::vector<Key> &keys)
{
if (mSign) {
for (const auto &key: keys) {
- const auto sigFmt = key.protocol() == GpgME::Protocol::OpenPGP ? AnyOpenPGP : AnySMIME;
- auto list = mSigKeys.value(sigFmt);
+ auto list = mSigKeys.value(key.protocol());
list.push_back(key);
- mSigKeys.insert(sigFmt, list);
+ mSigKeys.insert(key.protocol(), list);
}
}
}
// Try to find matching keys in the provided protocol for the unresolved addresses
// only updates the any maps.
- void resolveEnc(GpgME::Protocol proto)
+ void resolveEnc(Protocol proto)
{
- auto fmt = proto == GpgME::OpenPGP ? AnyOpenPGP : AnySMIME;
- auto encMap = mEncKeys.value(fmt);
- QMutableStringListIterator it((proto == GpgME::Protocol::OpenPGP) ? mUnresolvedPGP : mUnresolvedCMS);
+ auto encMap = mEncKeys.value(proto);
+ QMutableStringListIterator it((proto == Protocol::OpenPGP) ? mUnresolvedPGP : mUnresolvedCMS);
while (it.hasNext()) {
const QString addr = it.next();
const auto keys = mCache->findBestByMailBox(addr.toUtf8().constData(),
proto, false, true);
if (keys.empty() || keys[0].isNull()) {
qCDebug(LIBKLEO_LOG) << "Failed to find any"
- << (proto == GpgME::Protocol::OpenPGP ? "OpenPGP" : "CMS")
+ << (proto == Protocol::OpenPGP ? "OpenPGP" : "CMS")
<< "key for: " << addr;
continue;
}
if (keys.size() == 1) {
if (!isAcceptableEncryptionKey(keys[0], addr)) {
qCDebug(LIBKLEO_LOG) << "key for: " << addr << keys[0].primaryFingerprint()
<< "has not enough validity";
continue;
}
} else {
// If we have one unacceptable group key we reject the
// whole group to avoid the situation where one key is
// skipped or the operation fails.
//
// We are in Autoresolve land here. In the GUI we
// will also show unacceptable group keys so that the
// user can see which key is not acceptable.
bool unacceptable = false;
for (const auto &key: keys) {
if (!isAcceptableEncryptionKey(key)) {
qCDebug(LIBKLEO_LOG) << "group key for: " << addr << keys[0].primaryFingerprint()
<< "has not enough validity";
unacceptable = true;
break;
}
}
if (unacceptable) {
continue;
}
}
encMap.insert(addr, keys);
for (const auto &k: keys) {
if (!k.isNull()) {
qCDebug(LIBKLEO_LOG) << "Resolved encrypt to" << addr
<< "with key" << k.primaryFingerprint();
}
}
it.remove();
}
- mEncKeys.insert(fmt, encMap);
- }
-
- void encMapToSpecific(CryptoMessageFormat anyFormat, CryptoMessageFormat specificFormat,
- QMap<CryptoMessageFormat, QMap<QString, std::vector<GpgME::Key> > >&encMap)
- {
- Q_ASSERT(anyFormat & specificFormat);
- if (!encMap.contains(anyFormat)) {
- return;
- }
- for (const auto &addr: encMap[anyFormat].keys()) {
- if (!encMap.contains(specificFormat)) {
- encMap.insert(specificFormat, QMap<QString, std::vector<GpgME::Key> >());
- }
- encMap[specificFormat].insert(addr, encMap[anyFormat][addr]);
- }
- encMap.remove(anyFormat);
- }
-
- void reduceToSingle(CryptoMessageFormat targetFmt)
- {
- // We a have a specific format so we need to map any keys
- // into that format. This ignores overrides as the format
- // was explicitly set.
- CryptoMessageFormat srcFmt = (targetFmt & AnySMIME) ? AnySMIME : AnyOpenPGP;
- if (mSigKeys.contains(srcFmt)) {
- mSigKeys.insert(targetFmt, mSigKeys.take(srcFmt));
- }
- encMapToSpecific(srcFmt, targetFmt, mEncKeys);
- }
-
- void updateEncMap(QMap<QString, std::vector<GpgME::Key> > &target,
- QMap<QString, std::vector<GpgME::Key> > &src)
- {
- for (const auto &addr: target.keys()) {
- if (src.contains(addr)) {
- target.insert(addr, src[addr]);
- }
- }
- }
-
- void updateEncMaps(CryptoMessageFormat target, CryptoMessageFormat src)
- {
- if (mEncKeys.contains(src) && mEncKeys.contains(target)) {
- updateEncMap(mEncKeys[target], mEncKeys[src]);
- }
- }
-
- bool needsFormat(CryptoMessageFormat fmt)
- {
- return mEncKeys.contains(fmt);
- }
-
- void selectFormats()
- {
- // Check if we can find a single common specific format that works
- if (mFormat != AutoFormat && mFormat != AnyOpenPGP && mFormat != AnySMIME) {
- reduceToSingle(mFormat);
- }
-
- // OpenPGP
- // By default prefer OpenPGPMIME
- bool needTwoPGP = needsFormat(OpenPGPMIMEFormat) && needsFormat(InlineOpenPGPFormat);
- reduceToSingle(OpenPGPMIMEFormat);
- if (needTwoPGP) {
- // We need two messages as we have conflicting preferences.
-
- // Then we need to check that if we sign the PGP MIME Message we
- // also sign the inline one.
- if (mSigKeys.contains(OpenPGPMIMEFormat)) {
- mSigKeys.insert(InlineOpenPGPFormat,
- mSigKeys[OpenPGPMIMEFormat]);
- }
-
- // Then it's also possible that a user updated a key in the
- // UI so we need to check that too.
- updateEncMaps(InlineOpenPGPFormat, OpenPGPMIMEFormat);
- }
-
- // Similar for S/MIME
- bool needTwoSMIME = needsFormat(SMIMEOpaqueFormat) && needsFormat(SMIMEFormat);
- // Here we prefer real S/MIME
- reduceToSingle(SMIMEFormat);
- if (needTwoSMIME) {
- if (mSigKeys.contains(SMIMEFormat)) {
- mSigKeys.insert(SMIMEOpaqueFormat,
- mSigKeys[SMIMEFormat]);
- }
- updateEncMaps(SMIMEOpaqueFormat, SMIMEFormat);
- }
- return;
+ mEncKeys.insert(proto, encMap);
}
void showApprovalDialog(QWidget *parent)
{
- QMap<QString, std::vector<GpgME::Key> > resolvedSig;
+ QMap<QString, std::vector<Key> > resolvedSig;
QStringList unresolvedSig;
- bool pgpOnly = mUnresolvedPGP.empty() && (!mSign || mSigKeys.contains(AnyOpenPGP));
- bool cmsOnly = mUnresolvedCMS.empty() && (!mSign || mSigKeys.contains(AnySMIME));
+ bool pgpOnly = mUnresolvedPGP.empty() && (!mSign || mSigKeys.contains(OpenPGP));
+ bool cmsOnly = mUnresolvedCMS.empty() && (!mSign || mSigKeys.contains(CMS));
// First handle the signing keys
if (mSign) {
if (mSigKeys.empty()) {
unresolvedSig << mSender;
} else {
- std::vector<GpgME::Key> resolvedSigKeys;
+ std::vector<Key> resolvedSigKeys;
for (const auto &keys: qAsConst(mSigKeys)) {
for (const auto &key: keys) {
resolvedSigKeys.push_back(key);
}
}
resolvedSig.insert(mSender, resolvedSigKeys);
}
}
// Now build the encryption keys
- QMap<QString, std::vector<GpgME::Key> > resolvedRecp;
+ QMap<QString, std::vector<Key> > resolvedRecp;
QStringList unresolvedRecp;
if (mEncrypt) {
// Use all unresolved recipients.
if (!cmsOnly && !pgpOnly) {
- if (mFormat & AutoFormat) {
+ if (mFormat == UnknownProtocol) {
// In Auto Format we can now remove recipients that could
// be resolved either through CMS or PGP
for (const auto &addr: qAsConst(mUnresolvedPGP)) {
if (mUnresolvedCMS.contains(addr)) {
unresolvedRecp << addr;
}
}
- } else if (mFormat & AnyOpenPGP) {
+ } else if (mFormat == OpenPGP) {
unresolvedRecp = mUnresolvedPGP;
- } else if (mFormat & AnySMIME) {
+ } else if (mFormat == CMS) {
unresolvedRecp = mUnresolvedCMS;
}
}
// Now Map all resolved encryption keys regardless of the format.
for (const auto &map: mEncKeys.values()) {
// Foreach format
for (const auto &addr: map.keys()) {
// Foreach sender
if (!resolvedRecp.contains(addr) || !resolvedRecp[addr].size()) {
resolvedRecp.insert(addr, map[addr]);
} else {
- std::vector<GpgME::Key> merged = resolvedRecp[addr];
+ std::vector<Key> merged = resolvedRecp[addr];
// Add without duplication
for (const auto &k: map[addr]) {
- const auto it = std::find_if (merged.begin(), merged.end(), [k] (const GpgME::Key &y) {
+ const auto it = std::find_if (merged.begin(), merged.end(), [k] (const Key &y) {
return (k.primaryFingerprint() && y.primaryFingerprint() &&
!strcmp (k.primaryFingerprint(), y.primaryFingerprint()));
});
if (it == merged.end()) {
merged.push_back(k);
}
}
resolvedRecp[addr] = merged;
}
}
}
}
// Do we force the protocol?
- GpgME::Protocol forcedProto = mFormat == AutoFormat ? GpgME::UnknownProtocol :
- mFormat & AnyOpenPGP ? GpgME::OpenPGP :
- GpgME::CMS;
+ Protocol forcedProto = mFormat;
// Start with the protocol for which every keys could be found.
- GpgME::Protocol presetProtocol;
+ Protocol presetProtocol;
- if (mPreferredProtocol == GpgME::CMS && cmsOnly) {
- presetProtocol = GpgME::CMS;
+ if (mPreferredProtocol == CMS && cmsOnly) {
+ presetProtocol = CMS;
} else {
- presetProtocol = pgpOnly ? GpgME::OpenPGP :
- cmsOnly ? GpgME::CMS :
+ presetProtocol = pgpOnly ? OpenPGP :
+ cmsOnly ? CMS :
mPreferredProtocol;
}
mDialog = std::shared_ptr<NewKeyApprovalDialog>(new NewKeyApprovalDialog(resolvedSig,
resolvedRecp,
unresolvedSig,
unresolvedRecp,
mSender,
mAllowMixed,
forcedProto,
presetProtocol,
parent,
mDialogWindowFlags));
connect (mDialog.get(), &QDialog::accepted, q, [this] () {
dialogAccepted();
});
connect (mDialog.get(), &QDialog::rejected, q, [this] () {
Q_EMIT q->keysResolved(false, false);}
);
mDialog->open();
}
void dialogAccepted()
{
// Update keymaps accordingly
mSigKeys.clear();
for (const auto &key: mDialog->signingKeys()) {
- CryptoMessageFormat fmt = key.protocol() == GpgME::OpenPGP ? AnyOpenPGP : AnySMIME;
- if (!mSigKeys.contains(fmt)) {
- mSigKeys.insert(fmt, std::vector<GpgME::Key>());
+ if (!mSigKeys.contains(key.protocol())) {
+ mSigKeys.insert(key.protocol(), std::vector<Key>());
}
- mSigKeys[fmt].push_back(key);
+ mSigKeys[key.protocol()].push_back(key);
}
const auto &encMap = mDialog->encryptionKeys();
// First we clear the Any Maps and fill them with
// the results of the dialog. Then we use the sender
// address to determine if a keys in the specific
// maps need updating.
- mEncKeys.remove(AnyOpenPGP);
- mEncKeys.remove(AnySMIME);
+ mEncKeys.remove(OpenPGP);
+ mEncKeys.remove(CMS);
bool isUnresolved = false;
for (const auto &addr: encMap.keys()) {
for (const auto &key: encMap[addr]) {
if (key.isNull()) {
isUnresolved = true;
}
- CryptoMessageFormat fmt = key.protocol() == GpgME::OpenPGP ? AnyOpenPGP : AnySMIME;
- if (!mEncKeys.contains(fmt)) {
- mEncKeys.insert(fmt, QMap<QString, std::vector<GpgME::Key> >());
+ if (!mEncKeys.contains(key.protocol())) {
+ mEncKeys.insert(key.protocol(), QMap<QString, std::vector<Key> >());
}
- if (!mEncKeys[fmt].contains(addr)) {
- mEncKeys[fmt].insert(addr, std::vector<GpgME::Key>());
+ if (!mEncKeys[key.protocol()].contains(addr)) {
+ mEncKeys[key.protocol()].insert(addr, std::vector<Key>());
}
- qCDebug (LIBKLEO_LOG) << "Adding" << addr << "for" << cryptoMessageFormatToString (fmt)
+ qCDebug (LIBKLEO_LOG) << "Adding" << addr << "for" << Formatting::displayName(key.protocol())
<< "fpr:" << key.primaryFingerprint();
- mEncKeys[fmt][addr].push_back(key);
+ mEncKeys[key.protocol()][addr].push_back(key);
}
}
if (isUnresolved) {
// TODO show warning
}
Q_EMIT q->keysResolved(true, false);
}
KeyResolver *const q;
QString mSender;
QStringList mRecipients;
- QMap<CryptoMessageFormat, std::vector<GpgME::Key> > mSigKeys;
- QMap<CryptoMessageFormat, QMap<QString, std::vector<GpgME::Key> > >mEncKeys;
- QMap<CryptoMessageFormat, QMap<QString, QStringList> > mOverrides;
+ QMap<Protocol, std::vector<Key> > mSigKeys;
+ QMap<Protocol, QMap<QString, std::vector<Key> > >mEncKeys;
+ QMap<Protocol, QMap<QString, QStringList> > mOverrides;
QStringList mUnresolvedPGP, mUnresolvedCMS;
- CryptoMessageFormat mFormat;
+ Protocol mFormat;
QStringList mFatalErrors;
bool mEncrypt, mSign;
bool mAllowMixed;
// The cache is needed as a member variable to avoid rebuilding
// it between calls if we are the only user.
std::shared_ptr<const KeyCache> mCache;
std::shared_ptr<NewKeyApprovalDialog> mDialog;
Qt::WindowFlags mDialogWindowFlags;
- GpgME::Protocol mPreferredProtocol;
+ Protocol mPreferredProtocol;
int mMinimumValidity;
QString mCompliance;
};
void KeyResolver::start(bool showApproval, QWidget *parentWidget)
{
qCDebug(LIBKLEO_LOG) << "Starting ";
if (!d->mSign && !d->mEncrypt) {
// nothing to do
return Q_EMIT keysResolved(true, true);
}
// First resolve through overrides
d->resolveOverrides();
// Then look for signing / encryption keys
- if (d->mFormat & AnyOpenPGP) {
- d->resolveSign(GpgME::OpenPGP);
- d->resolveEnc(GpgME::OpenPGP);
+ if (d->mFormat != CMS) {
+ d->resolveSign(OpenPGP);
+ d->resolveEnc(OpenPGP);
}
- bool pgpOnly = d->mUnresolvedPGP.empty() && (!d->mSign || d->mSigKeys.contains(AnyOpenPGP));
+ bool pgpOnly = d->mUnresolvedPGP.empty() && (!d->mSign || d->mSigKeys.contains(OpenPGP));
- if (d->mFormat & AnySMIME) {
- d->resolveSign(GpgME::CMS);
- d->resolveEnc(GpgME::CMS);
+ if (d->mFormat != OpenPGP) {
+ d->resolveSign(CMS);
+ d->resolveEnc(CMS);
}
- bool cmsOnly = d->mUnresolvedCMS.empty() && (!d->mSign || d->mSigKeys.contains(AnySMIME));
+ bool cmsOnly = d->mUnresolvedCMS.empty() && (!d->mSign || d->mSigKeys.contains(CMS));
// Check if we need the user to select different keys.
bool needsUser = false;
if (!pgpOnly && !cmsOnly) {
for (const auto &unresolved: d->mUnresolvedPGP) {
if (d->mUnresolvedCMS.contains(unresolved)) {
// We have at least one unresolvable key.
needsUser = true;
break;
}
}
if (d->mSign) {
// So every recipient could be resolved through
// a combination of PGP and S/MIME do we also
// have signing keys for both?
- needsUser |= !(d->mSigKeys.contains(AnyOpenPGP) &&
- d->mSigKeys.contains(AnySMIME));
+ needsUser |= !(d->mSigKeys.contains(OpenPGP) &&
+ d->mSigKeys.contains(CMS));
}
}
if (!needsUser && !showApproval) {
if (pgpOnly) {
- d->mSigKeys.remove(AnySMIME);
- d->mEncKeys.remove(AnySMIME);
+ d->mSigKeys.remove(CMS);
+ d->mEncKeys.remove(CMS);
}
if (cmsOnly) {
- d->mSigKeys.remove(AnyOpenPGP);
- d->mEncKeys.remove(AnyOpenPGP);
+ d->mSigKeys.remove(OpenPGP);
+ d->mEncKeys.remove(OpenPGP);
}
- d->selectFormats();
qCDebug(LIBKLEO_LOG) << "Automatic key resolution done.";
Q_EMIT keysResolved(true, false);
return;
} else if (!needsUser) {
qCDebug(LIBKLEO_LOG) << "No need for the user showing approval anyway.";
}
d->showApprovalDialog(parentWidget);
}
-KeyResolver::KeyResolver(bool encrypt, bool sign, CryptoMessageFormat fmt, bool allowMixed)
+KeyResolver::KeyResolver(bool encrypt, bool sign, Protocol fmt, bool allowMixed)
: d(new Private(this, encrypt, sign, fmt, allowMixed))
{
}
Kleo::KeyResolver::~KeyResolver() = default;
void KeyResolver::setRecipients(const QStringList &addresses)
{
d->addRecpients(addresses);
}
void KeyResolver::setSender(const QString &address)
{
- const auto normalized = GpgME::UserID::addrSpecFromString (address.toUtf8().constData());
+ const auto normalized = UserID::addrSpecFromString (address.toUtf8().constData());
if (normalized.empty()) {
// should not happen bug in the caller, non localized
// error for bug reporting.
d->mFatalErrors << QStringLiteral("The sender address '%1' could not be extracted").arg(address);
return;
}
const auto normStr = QString::fromUtf8(normalized.c_str());
if (d->mSign) {
d->mSender = normStr;
}
if (d->mEncrypt) {
if (!d->mUnresolvedCMS.contains(normStr)) {
d->mUnresolvedCMS << normStr;
}
if (!d->mUnresolvedPGP.contains(normStr)) {
d->mUnresolvedPGP << normStr;
}
}
}
-void KeyResolver::setOverrideKeys(const QMap<CryptoMessageFormat, QMap<QString, QStringList> > &overrides)
+void KeyResolver::setOverrideKeys(const QMap<Protocol, QMap<QString, QStringList> > &overrides)
{
QMap<QString, QStringList> normalizedOverrides;
for (const auto fmt: overrides.keys()) {
for (const auto &addr: overrides[fmt].keys()) {
const auto normalized = QString::fromUtf8(
- GpgME::UserID::addrSpecFromString (addr.toUtf8().constData()).c_str());
+ UserID::addrSpecFromString (addr.toUtf8().constData()).c_str());
const auto fingerprints = overrides[fmt][addr];
normalizedOverrides.insert(addr, fingerprints);
}
d->mOverrides.insert(fmt, normalizedOverrides);
}
}
-QMap <CryptoMessageFormat, QMap<QString, std::vector<GpgME::Key> > > KeyResolver::encryptionKeys() const
+QMap <Protocol, QMap<QString, std::vector<Key> > > KeyResolver::encryptionKeys() const
{
return d->mEncKeys;
}
-QMap <CryptoMessageFormat, std::vector<GpgME::Key> > KeyResolver::signingKeys() const
+QMap <Protocol, std::vector<Key> > KeyResolver::signingKeys() const
{
return d->mSigKeys;
}
-QMap <CryptoMessageFormat, QMap<QString, QStringList> > KeyResolver::overrideKeys() const
+QMap <Protocol, QMap<QString, QStringList> > KeyResolver::overrideKeys() const
{
return d->mOverrides;
}
void KeyResolver::setDialogWindowFlags(Qt::WindowFlags flags)
{
d->mDialogWindowFlags = flags;
}
-void KeyResolver::setPreferredProtocol(GpgME::Protocol proto)
+void KeyResolver::setPreferredProtocol(Protocol proto)
{
d->mPreferredProtocol = proto;
}
void KeyResolver::setMinimumValidity(int validity)
{
d->mMinimumValidity = validity;
}
diff --git a/src/kleo/keyresolver.h b/src/kleo/keyresolver.h
index 35de4f85..cd64eacc 100644
--- a/src/kleo/keyresolver.h
+++ b/src/kleo/keyresolver.h
@@ -1,210 +1,210 @@
/* -*- c++ -*-
keyresolver.h
This file is part of libkleopatra, the KDE keymanagement library
SPDX-FileCopyrightText: 2018 Intevation GmbH
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef __KLEO_KEYRESOLVER_H__
#define __KLEO_KEYRESOLVER_H__
#include "kleo_export.h"
#include <Libkleo/Enum>
#include <QMap>
#include <QObject>
#include <QString>
#include <QStringList>
#include <gpgme++/global.h>
#include <memory>
#include <vector>
namespace GpgME
{
class Key;
}
namespace Kleo
{
/**
* Class to find Keys for E-Mail encryption.
*
* The KeyResolver uses the Keycache to find keys for signing
* or encryption.
*
* Overrides can be provided for address book integration if the
* format is not Auto overrides will only be respected if they
* match the format provided in the constructor.
*
* If no override key is provided for an address the key
* with a uid that matches the address and has the highest
* validity is used. If both keys have the same validity
* the newest subkey is used.
*
* The KeyResolver also supports groups so the number of
* encryption keys does not necessarily
* need to match the amount of sender addresses. For this reason
* maps are used heavily to map:
*
* CryptoFormat
* - Addresses
* -- For each Address a List of Keys
*
* As a caller you should iterate over the CryptoFormats and
* send one message for each format for the recipients and signed
* by the signing keys.
*
* If the CryptoMessageFormat is Auto the minimum number
* of CryptoMessageFormats is returned that respects all overrides.
*
* -----
* Planned:
*
* As the central place to manage mail encryption / signing keys
* the Keyresolver will also show various warning / nagging messages
* and offer solutions if nagging is not explicitly turned off.
* These include:
*
* - If own keys or subkeys are about to expire:
* Offer to extend their expiration date.
*
* - (S/MIME) If they are about to expire: Offer
* to generate a new CSR.
*
* - If a user has not marked a key as backed up and
* uses it for encryption for several mails.
*
* - If a user has multiple keys for a sender address and they
* are not cross signed. Offer to cross sign / publish.
*/
class KLEO_EXPORT KeyResolver : public QObject
{
Q_OBJECT
public:
/** Creates a new key resolver object.
*
* @param encrypt: Should encryption keys be selected.
* @param sign: Should signing keys be selected.
- * @param format: A specific format for selection. Default Auto.
+ * @param format: A specific key protocol (OpenPGP, S/MIME) for selection. Default: Both protocols.
* @param allowMixed: Specify if multiple message formats may be resolved.
**/
explicit KeyResolver(bool encrypt, bool sign,
- CryptoMessageFormat format = AutoFormat,
+ GpgME::Protocol format = GpgME::UnknownProtocol,
bool allowMixed = true);
~KeyResolver() override;
/**
* Set the list of recipient addresses. Also looks
* up possible keys, but doesn't interact with the user.
*
* @param addresses: A list of unnormalized addresses
*/
void setRecipients(const QStringList &addresses);
/**
* Set the senders address.
*
* Sender address will be added to encryption keys and used
* for signing key resolution if the signing keys are not
* explicitly set through setSigningKeys.
*
* @param sender: The sender of this message.
*/
void setSender(const QString &sender);
/**
* Set up possible override keys for recipients / sender
* addresses. The keys for the fingerprints are looked
* up and used when found. Does not interact with the user.
*
- * @param overrides: A map of \<cryptomessageformat\> -> (\<address\> \<fingerprints\>)
+ * @param overrides: A map of \<protocol\> -> (\<address\> \<fingerprints\>)
*/
- void setOverrideKeys(const QMap<CryptoMessageFormat, QMap<QString, QStringList> > &overrides);
+ void setOverrideKeys(const QMap<GpgME::Protocol, QMap<QString, QStringList> > &overrides);
/**
* Set explicit signing keys. If this was set for a
* protocol the sender address will be only used as an additional encryption
* recipient for that protocol. */
void setSigningKeys(const QStringList &fingerprints);
/**
* Set the minimum user id validity for autoresolution.
*
* The default value is marginal
*
* @param validity int representation of a GpgME::UserID::Validity.
*/
void setMinimumValidity(int validity);
/**
* Get the encryption keys after resolution.
*
* @return the resolved sender / key pairs for encryption by format.
*/
- QMap <CryptoMessageFormat, QMap<QString, std::vector<GpgME::Key> > > encryptionKeys() const;
+ QMap <GpgME::Protocol, QMap<QString, std::vector<GpgME::Key> > > encryptionKeys() const;
/**
* Get the signing keys to use after resolution.
*
* @return the resolved resolved sender / key pairs for signing
* by format.
*/
- QMap <CryptoMessageFormat, std::vector<GpgME::Key> > signingKeys() const;
+ QMap <GpgME::Protocol, std::vector<GpgME::Key> > signingKeys() const;
/**
* Starts the key resolving procedure. Emits keysResolved on success or
* error.
*
* @param showApproval: If set to true a dialog listing the keys
* will always be shown.
* @param parentWidget: Optional, a Widget to use as parent for dialogs.
*/
void start(bool showApproval, QWidget *parentWidget = nullptr);
/**
* Access possibly updated Override Keys
*
* @return A map of email's with new overrides and the according
* cryptoformat / fingerprint. Should be saved somehow.
*/
- QMap <CryptoMessageFormat, QMap<QString, QStringList> > overrideKeys() const;
+ QMap <GpgME::Protocol, QMap<QString, QStringList> > overrideKeys() const;
/**
* Set window flags for a possible dialog.
*/
void setDialogWindowFlags(Qt::WindowFlags flags);
/**
* Set the protocol that is preferred to be displayed first when
* it is not clear from the keys. E.g. if both OpenPGP and S/MIME
* can be resolved.
*/
void setPreferredProtocol(GpgME::Protocol proto);
Q_SIGNALS:
/**
* Emitted when key resolution finished.
*
* @param success: The general result. If true continue sending,
* if false abort.
* @param sendUnencrypted: If there could be no key found for one of
* the recipients the user was queried if the
* mail should be sent out unencrypted.
* sendUnencrypted is true if the user agreed
* to this.*/
void keysResolved(bool success, bool sendUnencrypted);
private:
class Private;
std::unique_ptr<Private> d;
};
} // namespace Kleo
#endif // __KLEO_KEYRESOLVER_H__
diff --git a/src/tests/test_keyresolver.cpp b/src/tests/test_keyresolver.cpp
index b9ead2c4..2727dac6 100644
--- a/src/tests/test_keyresolver.cpp
+++ b/src/tests/test_keyresolver.cpp
@@ -1,164 +1,159 @@
/*
test_keyresolver.cpp
This file is part of libkleopatra's test suite.
SPDX-FileCopyrightText: 2018 Intevation GmbH
SPDX-License-Identifier: GPL-2.0-only
*/
#include "kleo/keyresolver.h"
+#include "utils/formatting.h"
+
#include <QCommandLineParser>
#include <QApplication>
#include <QDebug>
#include <QTimer>
#include <gpgme++/key.h>
using namespace Kleo;
+using namespace GpgME;
-void dumpKeys(const QMap <CryptoMessageFormat, QMap<QString, std::vector<GpgME::Key> > > &fmtMap)
+void dumpKeys(const QMap <Protocol, QMap<QString, std::vector<Key> > > &fmtMap)
{
- for (const CryptoMessageFormat fmt: fmtMap.keys()) {
- qDebug () << "Format:" << cryptoMessageFormatToLabel(fmt) << fmt;
+ for (const Protocol fmt: fmtMap.keys()) {
+ qDebug () << "Format:" << Formatting::displayName(fmt) << fmt;
for (const auto &mbox: fmtMap[fmt].keys()) {
qDebug() << "Address:" << mbox;
qDebug() << "Keys:";
for (const auto &key: fmtMap[fmt][mbox]) {
qDebug () << key.primaryFingerprint();
}
}
}
}
-void dumpSigKeys(const QMap <CryptoMessageFormat, std::vector<GpgME::Key> > &fmtMap)
+void dumpSigKeys(const QMap <Protocol, std::vector<Key> > &fmtMap)
{
- for (const CryptoMessageFormat fmt: fmtMap.keys()) {
- qDebug () << "Format:" << cryptoMessageFormatToLabel(fmt) << fmt;
+ for (const Protocol fmt: fmtMap.keys()) {
+ qDebug () << "Format:" << Formatting::displayName(fmt) << fmt;
qDebug() << "Keys:";
for (const auto &key: fmtMap[fmt]) {
qDebug () << key.primaryFingerprint();
}
}
}
class SignalRecipient: public QObject
{
Q_OBJECT
public:
SignalRecipient(KeyResolver *res) : resolver(res) {}
void keysResolved(bool success, bool sendUnencrypted)
{
if (!success) {
qDebug() << "Canceled";
exit(1);
}
qDebug() << "Resolved Signing keys:";
dumpSigKeys (resolver->signingKeys());
qDebug() << "Resolved Encryption keys:";
dumpKeys (resolver->encryptionKeys());
qDebug() << "Send Unencrypted:" << sendUnencrypted;
exit(0);
}
private:
KeyResolver *resolver;
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QCommandLineParser parser;
parser.setApplicationDescription(QStringLiteral("Test KeyResolver class"));
parser.addHelpOption();
parser.addPositionalArgument(QStringLiteral("recipients"),
QStringLiteral("Recipients to resolve"),
QStringLiteral("[mailboxes]"));
parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("overrides")
<< QStringLiteral("o"),
QStringLiteral("Override where format can be:\n"
"InlineOpenPGP\n"
"OpenPGPMIME\n"
"SMIME\n"
"SMIMEOpaque\n"
"AnyOpenPGP\n"
"AnySMIME\n"
"Auto"),
QStringLiteral("mailbox:fpr,fpr,..:format")));
parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("sender")
<< QStringLiteral("s"),
QStringLiteral("Mailbox of the sender"),
QStringLiteral("mailbox")));
parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("sigkeys")
<< QStringLiteral("k"),
QStringLiteral("signing key"),
QStringLiteral("Explicit signing keys")));
parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("encrypt")
<< QStringLiteral("e"),
QStringLiteral("Only select encryption keys")));
parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("approval")
<< QStringLiteral("a"),
QStringLiteral("Always show approval dlg")));
parser.process(app);
const QStringList recps = parser.positionalArguments();
if (recps.size() < 1) {
parser.showHelp(1);
}
KeyResolver resolver(true, !parser.isSet(QStringLiteral("encrypt")));
resolver.setRecipients(recps);
resolver.setSender(parser.value(QStringLiteral("sender")));
- QMap <CryptoMessageFormat, QMap <QString, QStringList> > overrides;
+ QMap <Protocol, QMap <QString, QStringList> > overrides;
for (const QString &oride: parser.values(QStringLiteral("overrides"))) {
const QStringList split = oride.split(QLatin1Char(':'));
- CryptoMessageFormat fmt = AutoFormat;
+ Protocol fmt = UnknownProtocol;
if (split.size() < 2 || split.size() > 3) {
parser.showHelp(1);
}
if (split.size() == 3) {
const QString fmtStr = split[2].toLower();
- if (fmtStr == QLatin1String("inlineopenpgp")) {
- fmt = InlineOpenPGPFormat;
- } else if (fmtStr == QLatin1String("openpgpmime")) {
- fmt = OpenPGPMIMEFormat;
+ if (fmtStr == QLatin1String("openpgp")) {
+ fmt = OpenPGP;
} else if (fmtStr == QLatin1String("smime")) {
- fmt = SMIMEFormat;
- } else if (fmtStr == QLatin1String("smimeopaque")) {
- fmt = SMIMEOpaqueFormat;
- } else if (fmtStr == QLatin1String("anyopenpgp")) {
- fmt = AnyOpenPGP;
- } else if (fmtStr == QLatin1String("anysmime")) {
- fmt = AnySMIME;
+ fmt = CMS;
} else if (fmtStr == QLatin1String("auto")) {
- fmt = AutoFormat;
+ fmt = UnknownProtocol;
} else {
parser.showHelp(1);
}
}
const QStringList fingerprints = split[1].split(QLatin1Char(','));
auto map = overrides.value(fmt);
map.insert(split[0], fingerprints);
overrides.insert(fmt, map);
}
resolver.setOverrideKeys(overrides);
auto recp = new SignalRecipient(&resolver);
QObject::connect (&resolver, &KeyResolver::keysResolved, recp, &SignalRecipient::keysResolved);
QTimer::singleShot(1000, [&parser, &resolver]() {
resolver.start(parser.isSet(QStringLiteral("approval")));
});
app.exec();
return 0;
}
#include "test_keyresolver.moc"

File Metadata

Mime Type
text/x-diff
Expires
Sat, Apr 25, 3:20 PM (16 h, 44 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
0f/cc/980f29f775705ce06ef187a5651e

Event Timeline