Page MenuHome GnuPG

No OneTemporary

diff --git a/src/utils/keyhelpers.cpp b/src/utils/keyhelpers.cpp
index e0690923..5d454432 100644
--- a/src/utils/keyhelpers.cpp
+++ b/src/utils/keyhelpers.cpp
@@ -1,240 +1,262 @@
/*
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::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);
}
-bool Kleo::canBeUsedForSecretKeyOperations(const GpgME::Key &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 key.subkey(0).isSecret();
+ return subkey.isSecret();
#else
// older versions of GpgME did not always set the secret flag for card keys
- return key.subkey(0).isSecret() || key.subkey(0).isCardKey();
+ 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);
+ });
+}
+
+bool Kleo::canBeUsedForSecretKeyOperations(const GpgME::Key &key)
+{
+ return subkeyHasSecret(key.subkey(0));
+}
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));
}
diff --git a/src/utils/keyhelpers.h b/src/utils/keyhelpers.h
index 6b1b2361..80873e1c 100644
--- a/src/utils/keyhelpers.h
+++ b/src/utils/keyhelpers.h
@@ -1,172 +1,186 @@
/*
utils/keyhelpers.h
This file is part of libkleopatra, the KDE keymanagement library
SPDX-FileCopyrightText: 2021-2022 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "kleo_export.h"
#include <QStringList>
#include <gpgme++/key.h>
#include <algorithm>
#include <set>
#include <vector>
class QDate;
namespace Kleo
{
template<typename KeyContainer>
QStringList getFingerprints(const KeyContainer &keys)
{
QStringList fingerprints;
fingerprints.reserve(keys.size());
std::transform(std::begin(keys), std::end(keys), std::back_inserter(fingerprints), [](const auto &key) {
return QString::fromLatin1(key.primaryFingerprint());
});
return fingerprints;
}
KLEO_EXPORT std::set<QString> getMissingSignerKeyIds(const std::vector<GpgME::UserID> &userIds);
KLEO_EXPORT std::set<QString> getMissingSignerKeyIds(const std::vector<GpgME::Key> &keys);
/**
* Returns true, if the key \p key is the result of a lookup which is not present
* in the local key ring.
*/
KLEO_EXPORT bool isRemoteKey(const GpgME::Key &key);
KLEO_EXPORT GpgME::UserID::Validity minimalValidityOfNotRevokedUserIDs(const GpgME::Key &key);
KLEO_EXPORT GpgME::UserID::Validity maximalValidityOfUserIDs(const GpgME::Key &key);
/* Is the key valid i.e. are all not revoked uids fully trusted? */
KLEO_EXPORT bool allUserIDsHaveFullValidity(const GpgME::Key &key);
template<typename RangeOfKeys>
bool allKeysHaveProtocol(const RangeOfKeys &keys, GpgME::Protocol protocol)
{
return std::all_of(std::begin(keys), std::end(keys), [protocol](const auto &key) {
return key.protocol() == protocol;
});
}
template<typename RangeOfKeys>
bool anyKeyHasProtocol(const RangeOfKeys &keys, GpgME::Protocol protocol)
{
return std::any_of(std::begin(keys), std::end(keys), [protocol](const auto &key) {
return key.protocol() == protocol;
});
}
/** Returns true if \p signature is a self-signature. */
KLEO_EXPORT bool isSelfSignature(const GpgME::UserID::Signature &signature);
/**
* Returns true if the most recent self-signature of \p userId is a revocation
* signature or if it has expired.
*/
KLEO_EXPORT bool isRevokedOrExpired(const GpgME::UserID &userId);
/**
* Returns true if \p key can be used to certify user IDs, i.e. if the key
* has the required capability and if the secret key of the (primary)
* certification subkey is available in the keyring or on a smart card.
*/
KLEO_EXPORT bool canCreateCertifications(const GpgME::Key &key);
/**
* Returns true if the key \p key can be certified, i.e. it is an OpenPGP key
* which is neither revoked nor expired and which has at least one user ID
* that is neither revoked nor expired.
*/
KLEO_EXPORT bool canBeCertified(const GpgME::Key &key);
+/**
+ * Returns true if the certificate \p key can be used for encryption, i.e. if
+ * it has at least one encryption subkey that is neither expired nor revoked
+ * nor otherwise invalid.
+ */
+KLEO_EXPORT bool canBeUsedForEncryption(const GpgME::Key &key);
+
+/**
+ * Returns true if the certificate \p key can be used for signing data, i.e. if
+ * it has at least one signing subkey that is neither expired nor revoked
+ * nor otherwise invalid and for which the secret key is available.
+ */
+KLEO_EXPORT bool canBeUsedForSigning(const GpgME::Key &key);
+
/**
* Returns true if \p key can be used for operations requiring the secret key,
* i.e. if the secret key of the primary key pair is available in the keyring
* or on a smart card.
*
* \note Key::hasSecret() also returns true if a secret key stub, e.g. of an
* offline key, is available in the keyring.
*/
KLEO_EXPORT bool canBeUsedForSecretKeyOperations(const GpgME::Key &key);
/**
* Returns true if \p userId can be revoked, i.e. if it isn't the last valid
* user ID of an OpenPGP key.
*/
KLEO_EXPORT bool canRevokeUserID(const GpgME::UserID &userId);
/**
* Returns true if the secret key of the primary key pair of \p key is stored
* in the keyring.
*/
KLEO_EXPORT bool isSecretKeyStoredInKeyRing(const GpgME::Key &key);
/**
* Returns true if any keys suitable for certifying user IDs are available in
* the keyring or on a smart card.
*
* \sa canCreateCertifications
*/
KLEO_EXPORT bool userHasCertificationKey();
enum CertificationRevocationFeasibility {
CertificationCanBeRevoked = 0,
CertificationNotMadeWithOwnKey,
CertificationIsSelfSignature,
CertificationIsRevocation,
CertificationIsExpired,
CertificationIsInvalid,
CertificationKeyNotAvailable,
};
/**
* Checks if the user can revoke the given \p certification.
*/
KLEO_EXPORT CertificationRevocationFeasibility userCanRevokeCertification(const GpgME::UserID::Signature &certification);
/**
* Returns true if the user can revoke any of the certifications of the \p userId.
*
* \sa userCanRevokeCertification
*/
KLEO_EXPORT bool userCanRevokeCertifications(const GpgME::UserID &userId);
/**
* Returns true, if the user ID \p userID belongs to the key \p key.
*/
KLEO_EXPORT bool userIDBelongsToKey(const GpgME::UserID &userID, const GpgME::Key &key);
/**
* Returns a unary predicate to check if a user ID belongs to the key \p key.
*/
inline auto userIDBelongsToKey(const GpgME::Key &key)
{
return [key](const GpgME::UserID &userID) {
return userIDBelongsToKey(userID, key);
};
}
/**
* Returns true, if the two user IDs \p lhs and \p rhs are equal.
*
* Equality means that both user IDs belong to the same key, contain identical
* text, and have the same creation date (i.e. the creation date of the first
* self-signature is the same).
*/
KLEO_EXPORT bool userIDsAreEqual(const GpgME::UserID &lhs, const GpgME::UserID &rhs);
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Jan 3, 11:45 PM (4 h, 22 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
d7/b6/be3a2a30959c25253769c6bca332

Event Timeline