Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F35382224
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
11 KB
Subscribers
None
View Options
diff --git a/src/utils/keyhelpers.cpp b/src/utils/keyhelpers.cpp
index ccbf196e..b2e24ff6 100644
--- a/src/utils/keyhelpers.cpp
+++ b/src/utils/keyhelpers.cpp
@@ -1,309 +1,293 @@
/*
utils/keyhelpers.cpp
This file is part of libkleopatra, the KDE keymanagement library
SPDX-FileCopyrightText: 2022 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-libkleo.h>
#include "keyhelpers.h"
#include <libkleo/algorithm.h>
#include <libkleo/compat.h>
#include <libkleo/keycache.h>
#include <libkleo_debug.h>
#include <QDate>
-// needed for GPGME_VERSION_NUMBER
-#include <gpgme.h>
-
#include <algorithm>
#include <iterator>
using namespace Kleo;
using namespace GpgME;
namespace
{
bool havePublicKeyForSignature(const GpgME::UserID::Signature &signature)
{
// GnuPG returns status "NoPublicKey" for missing signing keys, but also
// for expired or revoked signing keys.
return (signature.status() != GpgME::UserID::Signature::NoPublicKey) //
|| !KeyCache::instance()->findByKeyIDOrFingerprint(signature.signerKeyID()).isNull();
}
auto _getMissingSignerKeyIds(const std::vector<GpgME::UserID::Signature> &signatures)
{
return std::accumulate(std::begin(signatures), std::end(signatures), std::set<QString>{}, [](auto &keyIds, const auto &signature) {
if (!havePublicKeyForSignature(signature)) {
keyIds.insert(QLatin1String{signature.signerKeyID()});
}
return keyIds;
});
}
}
std::set<QString> Kleo::getMissingSignerKeyIds(const std::vector<GpgME::UserID> &userIds)
{
return std::accumulate(std::begin(userIds), std::end(userIds), std::set<QString>{}, [](auto &keyIds, const auto &userID) {
if (!userID.isBad()) {
const auto newKeyIds = _getMissingSignerKeyIds(userID.signatures());
std::copy(std::begin(newKeyIds), std::end(newKeyIds), std::inserter(keyIds, std::end(keyIds)));
}
return keyIds;
});
}
std::set<QString> Kleo::getMissingSignerKeyIds(const std::vector<GpgME::Key> &keys)
{
return std::accumulate(std::begin(keys), std::end(keys), std::set<QString>{}, [](auto &keyIds, const auto &key) {
if (!key.isBad()) {
const auto newKeyIds = getMissingSignerKeyIds(key.userIDs());
std::copy(std::begin(newKeyIds), std::end(newKeyIds), std::inserter(keyIds, std::end(keyIds)));
}
return keyIds;
});
}
bool Kleo::isRemoteKey(const GpgME::Key &key)
{
// a remote key looked up via WKD has key list mode Local; therefore we also look for the key in the local key ring
return (key.keyListMode() == GpgME::Extern) || KeyCache::instance()->findByFingerprint(key.primaryFingerprint()).isNull();
}
GpgME::UserID::Validity Kleo::minimalValidityOfNotRevokedUserIDs(const Key &key)
{
const std::vector<UserID> userIDs = key.userIDs();
const int minValidity = std::accumulate(userIDs.begin(), userIDs.end(), UserID::Ultimate + 1, [](int validity, const UserID &userID) {
return userID.isRevoked() ? validity : std::min(validity, static_cast<int>(userID.validity()));
});
return minValidity <= UserID::Ultimate ? static_cast<UserID::Validity>(minValidity) : UserID::Unknown;
}
GpgME::UserID::Validity Kleo::maximalValidityOfUserIDs(const Key &key)
{
const auto userIDs = key.userIDs();
const int maxValidity = std::accumulate(userIDs.begin(), userIDs.end(), 0, [](int validity, const UserID &userID) {
return std::max(validity, static_cast<int>(userID.validity()));
});
return static_cast<UserID::Validity>(maxValidity);
}
bool Kleo::allUserIDsHaveFullValidity(const GpgME::Key &key)
{
return minimalValidityOfNotRevokedUserIDs(key) >= UserID::Full;
}
namespace
{
bool isLastValidUserID(const GpgME::UserID &userId)
{
if (Kleo::isRevokedOrExpired(userId)) {
return false;
}
const auto userIds = userId.parent().userIDs();
const int numberOfValidUserIds = std::count_if(std::begin(userIds), std::end(userIds), [](const auto &u) {
return !Kleo::isRevokedOrExpired(u);
});
return numberOfValidUserIds == 1;
}
bool hasValidUserID(const GpgME::Key &key)
{
return Kleo::any_of(key.userIDs(), [](const auto &u) {
return !Kleo::isRevokedOrExpired(u);
});
}
}
bool Kleo::isSelfSignature(const GpgME::UserID::Signature &signature)
{
return !qstrcmp(signature.parent().parent().keyID(), signature.signerKeyID());
}
bool Kleo::isRevokedOrExpired(const GpgME::UserID &userId)
{
if (userId.isRevoked() || userId.parent().isExpired()) {
return true;
}
const auto sigs = userId.signatures();
std::vector<GpgME::UserID::Signature> selfSigs;
std::copy_if(std::begin(sigs), std::end(sigs), std::back_inserter(selfSigs), &Kleo::isSelfSignature);
std::sort(std::begin(selfSigs), std::end(selfSigs));
// check the most recent signature
const auto sig = !selfSigs.empty() ? selfSigs.back() : GpgME::UserID::Signature{};
return !sig.isNull() && (sig.isRevokation() || sig.isExpired());
}
bool Kleo::isExpired(const UserID &userID)
{
if (userID.parent().isExpired()) {
return true;
}
const auto sigs = userID.signatures();
std::vector<GpgME::UserID::Signature> selfSigs;
std::copy_if(std::begin(sigs), std::end(sigs), std::back_inserter(selfSigs), &Kleo::isSelfSignature);
std::sort(std::begin(selfSigs), std::end(selfSigs));
// check the most recent signature
const auto sig = !selfSigs.empty() ? selfSigs.back() : GpgME::UserID::Signature{};
return !sig.isNull() && sig.isExpired();
}
bool Kleo::canCreateCertifications(const GpgME::Key &key)
{
return Kleo::keyHasCertify(key) && canBeUsedForSecretKeyOperations(key);
}
bool Kleo::canBeCertified(const GpgME::Key &key)
{
return key.protocol() == GpgME::OpenPGP //
&& !key.isBad() //
&& hasValidUserID(key);
}
-namespace
-{
-static inline bool subkeyHasSecret(const GpgME::Subkey &subkey)
-{
-#if GPGME_VERSION_NUMBER >= 0x011102 // 1.17.2
- // we need to check the primary subkey because Key::hasSecret() is also true if just the secret key stub of an offline key is available
- return subkey.isSecret();
-#else
- // older versions of GpgME did not always set the secret flag for card keys
- return subkey.isSecret() || subkey.isCardKey();
-#endif
-}
-}
-
bool Kleo::canBeUsedForEncryption(const GpgME::Key &key)
{
return !key.isBad() && Kleo::any_of(key.subkeys(), [](const auto &subkey) {
return subkey.canEncrypt() && !subkey.isBad();
});
}
bool Kleo::canBeUsedForSigning(const GpgME::Key &key)
{
return !key.isBad() && Kleo::any_of(key.subkeys(), [](const auto &subkey) {
- return subkey.canSign() && !subkey.isBad() && subkeyHasSecret(subkey);
+ return subkey.canSign() && !subkey.isBad() && subkey.isSecret();
});
}
bool Kleo::canBeUsedForSecretKeyOperations(const GpgME::Key &key)
{
- return subkeyHasSecret(key.subkey(0));
+ // we need to check the primary subkey because Key::hasSecret() is also true if just the secret key stub of an offline key is available
+ return key.subkey(0).isSecret();
}
bool Kleo::canRevokeUserID(const GpgME::UserID &userId)
{
return (!userId.isNull() //
&& userId.parent().protocol() == GpgME::OpenPGP //
&& !isLastValidUserID(userId));
}
bool Kleo::isSecretKeyStoredInKeyRing(const GpgME::Key &key)
{
return key.subkey(0).isSecret() && !key.subkey(0).isCardKey();
}
bool Kleo::userHasCertificationKey()
{
const auto secretKeys = KeyCache::instance()->secretKeys();
return Kleo::any_of(secretKeys, [](const auto &k) {
return (k.protocol() == GpgME::OpenPGP) && canCreateCertifications(k);
});
}
Kleo::CertificationRevocationFeasibility Kleo::userCanRevokeCertification(const GpgME::UserID::Signature &certification)
{
const auto certificationKey = KeyCache::instance()->findByKeyIDOrFingerprint(certification.signerKeyID());
const bool isSelfSignature = qstrcmp(certification.parent().parent().keyID(), certification.signerKeyID()) == 0;
if (!certificationKey.hasSecret()) {
return CertificationNotMadeWithOwnKey;
} else if (isSelfSignature) {
return CertificationIsSelfSignature;
} else if (certification.isRevokation()) {
return CertificationIsRevocation;
} else if (certification.isExpired()) {
return CertificationIsExpired;
} else if (certification.isInvalid()) {
return CertificationIsInvalid;
} else if (!canCreateCertifications(certificationKey)) {
return CertificationKeyNotAvailable;
}
return CertificationCanBeRevoked;
}
bool Kleo::userCanRevokeCertifications(const GpgME::UserID &userId)
{
if (userId.numSignatures() == 0) {
qCWarning(LIBKLEO_LOG) << __func__ << "- Error: Signatures of user ID" << QString::fromUtf8(userId.id()) << "not available";
}
return Kleo::any_of(userId.signatures(), [](const auto &certification) {
return userCanRevokeCertification(certification) == CertificationCanBeRevoked;
});
}
bool Kleo::userIDBelongsToKey(const GpgME::UserID &userID, const GpgME::Key &key)
{
return !qstricmp(userID.parent().primaryFingerprint(), key.primaryFingerprint());
}
static time_t creationDate(const GpgME::UserID &uid)
{
// returns the date of the first self-signature
for (unsigned int i = 0, numSignatures = uid.numSignatures(); i < numSignatures; ++i) {
const auto sig = uid.signature(i);
if (Kleo::isSelfSignature(sig)) {
return sig.creationTime();
}
}
return 0;
}
bool Kleo::userIDsAreEqual(const GpgME::UserID &lhs, const GpgME::UserID &rhs)
{
return (qstrcmp(lhs.parent().primaryFingerprint(), rhs.parent().primaryFingerprint()) == 0 //
&& qstrcmp(lhs.id(), rhs.id()) == 0 //
&& creationDate(lhs) == creationDate(rhs));
}
static inline bool isOpenPGPCertification(const GpgME::UserID::Signature &sig)
{
// certification class is 0x10, ..., 0x13
return (sig.certClass() & ~0x03) == 0x10;
}
static bool isOpenPGPCertificationByUser(const GpgME::UserID::Signature &sig)
{
if (!isOpenPGPCertification(sig)) {
return false;
}
const auto certificationKey = KeyCache::instance()->findByKeyIDOrFingerprint(sig.signerKeyID());
return certificationKey.ownerTrust() == Key::Ultimate;
}
bool Kleo::userIDIsCertifiedByUser(const GpgME::UserID &userId)
{
if (userId.parent().protocol() != GpgME::OpenPGP) {
qCWarning(LIBKLEO_LOG) << __func__ << "not called with OpenPGP key";
return false;
}
if (userId.numSignatures() == 0) {
qCWarning(LIBKLEO_LOG) << __func__ << "- Error: Signatures of user ID" << QString::fromUtf8(userId.id()) << "not available";
}
for (unsigned int i = 0, numSignatures = userId.numSignatures(); i < numSignatures; ++i) {
const auto sig = userId.signature(i);
if ((sig.status() == UserID::Signature::NoError) && !sig.isBad() && sig.isExportable() && isOpenPGPCertificationByUser(sig)) {
return true;
}
}
return false;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Feb 7, 7:30 AM (19 h, 39 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
1c/25/93229e559553842b4599a8373010
Attached To
rLIBKLEO Libkleo
Event Timeline
Log In to Comment