11#include <config-libkleo.h> 
   13#include "keyhelpers.h" 
   15#include <libkleo/algorithm.h> 
   16#include <libkleo/compat.h> 
   17#include <libkleo/keycache.h> 
   19#include <libkleo_debug.h> 
   30bool havePublicKeyForSignature(
const GpgME::UserID::Signature &signature)
 
   34    return (signature.status() != GpgME::UserID::Signature::NoPublicKey) 
 
   35        || !KeyCache::instance()->findByKeyIDOrFingerprint(signature.signerKeyID()).isNull();
 
   38auto _getMissingSignerKeyIds(
const std::vector<GpgME::UserID::Signature> &signatures)
 
   40    return std::accumulate(std::begin(signatures), std::end(signatures), std::set<QString>{}, [](
auto keyIds, 
const auto &signature) {
 
   41        if (!havePublicKeyForSignature(signature)) {
 
   49std::set<QString> Kleo::getMissingSignerKeyIds(
const std::vector<GpgME::UserID> &userIds)
 
   51    return std::accumulate(std::begin(userIds), std::end(userIds), std::set<QString>{}, [](
auto keyIds, 
const auto &userID) {
 
   52        if (!userID.isBad()) {
 
   53            const auto newKeyIds = _getMissingSignerKeyIds(userID.signatures());
 
   54            std::copy(std::begin(newKeyIds), std::end(newKeyIds), std::inserter(keyIds, std::end(keyIds)));
 
   60std::set<QString> Kleo::getMissingSignerKeyIds(
const std::vector<GpgME::Key> &keys)
 
   62    return std::accumulate(std::begin(keys), std::end(keys), std::set<QString>{}, [](
auto keyIds, 
const auto &key) {
 
   64            const auto newKeyIds = getMissingSignerKeyIds(key.userIDs());
 
   65            std::copy(std::begin(newKeyIds), std::end(newKeyIds), std::inserter(keyIds, std::end(keyIds)));
 
   71bool Kleo::isRemoteKey(
const GpgME::Key &key)
 
   74    return (key.keyListMode() == GpgME::Extern) || KeyCache::instance()->findByFingerprint(key.primaryFingerprint()).isNull();
 
   77GpgME::UserID::Validity Kleo::minimalValidityOfNotRevokedUserIDs(
const Key &key)
 
   79    const std::vector<UserID> userIDs = key.userIDs();
 
   80    const int minValidity = std::accumulate(userIDs.begin(), userIDs.end(), UserID::Ultimate + 1, [](
int validity, 
const UserID &userID) {
 
   81        return userID.isRevoked() ? validity : std::min(validity, static_cast<int>(userID.validity()));
 
   83    return minValidity <= UserID::Ultimate ? static_cast<UserID::Validity>(minValidity) : UserID::
Unknown;
 
   86GpgME::UserID::Validity Kleo::maximalValidityOfUserIDs(
const Key &key)
 
   88    const auto userIDs = key.userIDs();
 
   89    const int maxValidity = std::accumulate(userIDs.begin(), userIDs.end(), 0, [](
int validity, 
const UserID &userID) {
 
   90        return std::max(validity, static_cast<int>(userID.validity()));
 
   92    return static_cast<UserID::Validity
>(maxValidity);
 
   95bool Kleo::allUserIDsHaveFullValidity(
const GpgME::Key &key)
 
   97    return minimalValidityOfNotRevokedUserIDs(key) >= UserID::Full;
 
  102bool isLastValidUserID(
const GpgME::UserID &userId)
 
  104    if (Kleo::isRevokedOrExpired(userId)) {
 
  107    const auto userIds = userId.parent().userIDs();
 
  108    const int numberOfValidUserIds = std::count_if(std::begin(userIds), std::end(userIds), [](
const auto &u) {
 
  109        return !Kleo::isRevokedOrExpired(u);
 
  111    return numberOfValidUserIds == 1;
 
  114bool hasValidUserID(
const GpgME::Key &key)
 
  116    return Kleo::any_of(key.userIDs(), [](
const auto &u) {
 
  117        return !Kleo::isRevokedOrExpired(u);
 
  122bool Kleo::isSelfSignature(
const GpgME::UserID::Signature &signature)
 
  124    return !qstrcmp(signature.parent().parent().keyID(), signature.signerKeyID());
 
  127bool Kleo::isRevokedOrExpired(
const GpgME::UserID &userId)
 
  129    if (userId.isRevoked() || userId.parent().isExpired()) {
 
  132    const auto sigs = userId.signatures();
 
  133    std::vector<GpgME::UserID::Signature> selfSigs;
 
  134    std::copy_if(std::begin(sigs), std::end(sigs), std::back_inserter(selfSigs), &Kleo::isSelfSignature);
 
  135    std::sort(std::begin(selfSigs), std::end(selfSigs));
 
  137    const auto sig = !selfSigs.empty() ? selfSigs.back() : GpgME::UserID::Signature{};
 
  138    return !sig.isNull() && (sig.isRevokation() || sig.isExpired());
 
  141bool Kleo::isExpired(
const UserID &userID)
 
  143    if (userID.parent().isExpired()) {
 
  146    const auto sigs = userID.signatures();
 
  147    std::vector<GpgME::UserID::Signature> selfSigs;
 
  148    std::copy_if(std::begin(sigs), std::end(sigs), std::back_inserter(selfSigs), &Kleo::isSelfSignature);
 
  149    std::sort(std::begin(selfSigs), std::end(selfSigs));
 
  151    const auto sig = !selfSigs.empty() ? selfSigs.back() : GpgME::UserID::Signature{};
 
  152    return !sig.isNull() && sig.isExpired();
 
  155bool Kleo::canCreateCertifications(
const GpgME::Key &key)
 
  157    return Kleo::keyHasCertify(key) && canBeUsedForSecretKeyOperations(key);
 
  160bool Kleo::canBeCertified(
const GpgME::Key &key)
 
  162    return key.protocol() == GpgME::OpenPGP 
 
  164        && hasValidUserID(key);
 
  167bool Kleo::canBeUsedForEncryption(
const GpgME::Key &key)
 
  169    return !key.isBad() && Kleo::any_of(key.subkeys(), [](
const auto &subkey) {
 
  170        return subkey.canEncrypt() && !subkey.isBad();
 
  174bool Kleo::canBeUsedForSigning(
const GpgME::Key &key)
 
  176    return !key.isBad() && Kleo::any_of(key.subkeys(), [](
const auto &subkey) {
 
  177        return subkey.canSign() && !subkey.isBad() && subkey.isSecret();
 
  181bool Kleo::canBeUsedForSecretKeyOperations(
const GpgME::Key &key)
 
  184    return key.subkey(0).isSecret();
 
  187bool Kleo::canRevokeUserID(
const GpgME::UserID &userId)
 
  189    return (!userId.isNull() 
 
  190            && userId.parent().protocol() == GpgME::OpenPGP 
 
  191            && !isLastValidUserID(userId));
 
  194bool Kleo::isSecretKeyStoredInKeyRing(
const GpgME::Key &key)
 
  196    return key.subkey(0).isSecret() && !key.subkey(0).isCardKey();
 
  199bool Kleo::userHasCertificationKey()
 
  201    const auto secretKeys = KeyCache::instance()->secretKeys();
 
  202    return Kleo::any_of(secretKeys, [](
const auto &k) {
 
  203        return (k.protocol() == GpgME::OpenPGP) && canCreateCertifications(k);
 
  207Kleo::CertificationRevocationFeasibility Kleo::userCanRevokeCertification(
const GpgME::UserID::Signature &certification)
 
  209    const auto certificationKey = KeyCache::instance()->findByKeyIDOrFingerprint(certification.signerKeyID());
 
  210    const bool isSelfSignature = qstrcmp(certification.parent().parent().keyID(), certification.signerKeyID()) == 0;
 
  211    if (!certificationKey.hasSecret()) {
 
  212        return CertificationNotMadeWithOwnKey;
 
  213    } 
else if (isSelfSignature) {
 
  214        return CertificationIsSelfSignature;
 
  215    } 
else if (certification.isRevokation()) {
 
  216        return CertificationIsRevocation;
 
  217    } 
else if (certification.isExpired()) {
 
  218        return CertificationIsExpired;
 
  219    } 
else if (certification.isInvalid()) {
 
  220        return CertificationIsInvalid;
 
  221    } 
else if (!canCreateCertifications(certificationKey)) {
 
  222        return CertificationKeyNotAvailable;
 
  224    return CertificationCanBeRevoked;
 
  227bool Kleo::userCanRevokeCertifications(
const GpgME::UserID &userId)
 
  229    if (userId.numSignatures() == 0) {
 
  230        qCWarning(LIBKLEO_LOG) << __func__ << 
"- Error: Signatures of user ID" << 
QString::fromUtf8(userId.id()) << 
"not available";
 
  232    return Kleo::any_of(userId.signatures(), [](
const auto &certification) {
 
  233        return userCanRevokeCertification(certification) == CertificationCanBeRevoked;
 
  237bool Kleo::userIDBelongsToKey(
const GpgME::UserID &userID, 
const GpgME::Key &key)
 
  239    return !qstricmp(userID.parent().primaryFingerprint(), key.primaryFingerprint());
 
  242static time_t creationDate(
const GpgME::UserID &uid)
 
  245    for (
unsigned int i = 0, numSignatures = uid.numSignatures(); i < numSignatures; ++i) {
 
  246        const auto sig = uid.signature(i);
 
  247        if (Kleo::isSelfSignature(sig)) {
 
  248            return sig.creationTime();
 
  254bool Kleo::userIDsAreEqual(
const GpgME::UserID &lhs, 
const GpgME::UserID &rhs)
 
  256    return (qstrcmp(lhs.parent().primaryFingerprint(), rhs.parent().primaryFingerprint()) == 0 
 
  257            && qstrcmp(lhs.id(), rhs.id()) == 0 
 
  258            && creationDate(lhs) == creationDate(rhs));
 
  261static inline bool isOpenPGPCertification(
const GpgME::UserID::Signature &sig)
 
  264    return (sig.certClass() & ~0x03) == 0x10;
 
  267static bool isOpenPGPCertificationByUser(
const GpgME::UserID::Signature &sig)
 
  269    if (!isOpenPGPCertification(sig)) {
 
  272    const auto certificationKey = KeyCache::instance()->findByKeyIDOrFingerprint(sig.signerKeyID());
 
  273    return certificationKey.ownerTrust() == Key::Ultimate;
 
  276bool Kleo::userIDIsCertifiedByUser(
const GpgME::UserID &userId)
 
  278    if (userId.parent().protocol() != GpgME::OpenPGP) {
 
  279        qCWarning(LIBKLEO_LOG) << __func__ << 
"not called with OpenPGP key";
 
  282    if (userId.numSignatures() == 0) {
 
  283        qCWarning(LIBKLEO_LOG) << __func__ << 
"- Error: Signatures of user ID" << 
QString::fromUtf8(userId.id()) << 
"not available";
 
  285    for (
unsigned int i = 0, numSignatures = userId.numSignatures(); i < numSignatures; ++i) {
 
  286        const auto sig = userId.signature(i);
 
  287        if ((sig.status() == UserID::Signature::NoError) && !sig.isBad() && sig.isExportable() && isOpenPGPCertificationByUser(sig)) {
 
QString fromUtf8(QByteArrayView str)