diff --git a/lang/cpp/src/key.cpp b/lang/cpp/src/key.cpp index 61b3eb77..8fc266ff 100644 --- a/lang/cpp/src/key.cpp +++ b/lang/cpp/src/key.cpp @@ -1,1075 +1,1078 @@ /* key.cpp - wraps a gpgme key Copyright (C) 2003, 2005 Klarälvdalens Datakonsult AB This file is part of GPGME++. GPGME++ is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GPGME++ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with GPGME++; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "util.h" #include "tofuinfo.h" #include "context.h" #include #include #include #include #include const GpgME::Key::Null GpgME::Key::null; namespace GpgME { Key::Key() : key() {} Key::Key(const Null &) : key() {} Key::Key(const shared_gpgme_key_t &k) : key(k) {} Key::Key(gpgme_key_t k, bool ref) : key(k ? shared_gpgme_key_t(k, &gpgme_key_unref) : shared_gpgme_key_t()) { if (ref && impl()) { gpgme_key_ref(impl()); } } UserID Key::userID(unsigned int index) const { return UserID(key, index); } Subkey Key::subkey(unsigned int index) const { return Subkey(key, index); } unsigned int Key::numUserIDs() const { if (!key) { return 0; } unsigned int count = 0; for (gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next) { ++count; } return count; } unsigned int Key::numSubkeys() const { if (!key) { return 0; } unsigned int count = 0; for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) { ++count; } return count; } std::vector Key::userIDs() const { if (!key) { return std::vector(); } std::vector v; v.reserve(numUserIDs()); for (gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next) { v.push_back(UserID(key, uid)); } return v; } std::vector Key::subkeys() const { if (!key) { return std::vector(); } std::vector v; v.reserve(numSubkeys()); for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) { v.push_back(Subkey(key, subkey)); } return v; } Key::OwnerTrust Key::ownerTrust() const { if (!key) { return Unknown; } switch (key->owner_trust) { default: case GPGME_VALIDITY_UNKNOWN: return Unknown; case GPGME_VALIDITY_UNDEFINED: return Undefined; case GPGME_VALIDITY_NEVER: return Never; case GPGME_VALIDITY_MARGINAL: return Marginal; case GPGME_VALIDITY_FULL: return Full; case GPGME_VALIDITY_ULTIMATE: return Ultimate; } } char Key::ownerTrustAsString() const { if (!key) { return '?'; } switch (key->owner_trust) { default: case GPGME_VALIDITY_UNKNOWN: return '?'; case GPGME_VALIDITY_UNDEFINED: return 'q'; case GPGME_VALIDITY_NEVER: return 'n'; case GPGME_VALIDITY_MARGINAL: return 'm'; case GPGME_VALIDITY_FULL: return 'f'; case GPGME_VALIDITY_ULTIMATE: return 'u'; } } Protocol Key::protocol() const { if (!key) { return UnknownProtocol; } switch (key->protocol) { case GPGME_PROTOCOL_CMS: return CMS; case GPGME_PROTOCOL_OpenPGP: return OpenPGP; default: return UnknownProtocol; } } const char *Key::protocolAsString() const { return key ? gpgme_get_protocol_name(key->protocol) : 0 ; } bool Key::isRevoked() const { return key && key->revoked; } bool Key::isExpired() const { return key && key->expired; } bool Key::isDisabled() const { return key && key->disabled; } bool Key::isInvalid() const { return key && key->invalid; } bool Key::hasSecret() const { return key && key->secret; } bool Key::isRoot() const { return key && key->subkeys && key->subkeys->fpr && key->chain_id && strcasecmp(key->subkeys->fpr, key->chain_id) == 0; } bool Key::canEncrypt() const { return key && key->can_encrypt; } bool Key::canSign() const { #ifndef GPGME_CAN_SIGN_ON_SECRET_OPENPGP_KEYLISTING_NOT_BROKEN if (key && key->protocol == GPGME_PROTOCOL_OpenPGP) { return true; } #endif return canReallySign(); } bool Key::canReallySign() const { return key && key->can_sign; } bool Key::canCertify() const { return key && key->can_certify; } bool Key::canAuthenticate() const { return key && key->can_authenticate; } bool Key::isQualified() const { return key && key->is_qualified; } bool Key::isDeVs() const { if (!key) { return false; } if (!key->subkeys || !key->subkeys->is_de_vs) { return false; } for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) { if (!subkey->is_de_vs) { return false; } } return true; } const char *Key::issuerSerial() const { return key ? key->issuer_serial : 0 ; } const char *Key::issuerName() const { return key ? key->issuer_name : 0 ; } const char *Key::chainID() const { return key ? key->chain_id : 0 ; } const char *Key::keyID() const { return key && key->subkeys ? key->subkeys->keyid : 0 ; } const char *Key::shortKeyID() const { if (!key || !key->subkeys || !key->subkeys->keyid) { return 0; } const int len = strlen(key->subkeys->keyid); if (len > 8) { return key->subkeys->keyid + len - 8; // return the last 8 bytes (in hex notation) } else { return key->subkeys->keyid; } } const char *Key::primaryFingerprint() const { if (!key) { return nullptr; } if (key->fpr) { /* Return what gpgme thinks is the primary fingerprint */ return key->fpr; } if (key->subkeys) { /* Return the first subkeys fingerprint */ return key->subkeys->fpr; } return nullptr; } unsigned int Key::keyListMode() const { return key ? convert_from_gpgme_keylist_mode_t(key->keylist_mode) : 0 ; } const Key &Key::mergeWith(const Key &other) { // ### incomplete. Just merges has* and can*, nothing else atm // ### detach also missing if (!this->primaryFingerprint() || !other.primaryFingerprint() || strcasecmp(this->primaryFingerprint(), other.primaryFingerprint()) != 0) { return *this; // only merge the Key object which describe the same key } const gpgme_key_t me = impl(); const gpgme_key_t him = other.impl(); if (!me || !him) { return *this; } me->revoked |= him->revoked; me->expired |= him->expired; me->disabled |= him->disabled; me->invalid |= him->invalid; me->can_encrypt |= him->can_encrypt; me->can_sign |= him->can_sign; me->can_certify |= him->can_certify; me->secret |= him->secret; me->can_authenticate |= him->can_authenticate; me->is_qualified |= him->is_qualified; me->keylist_mode |= him->keylist_mode; // make sure the gpgme_sub_key_t::is_cardkey flag isn't lost: for (gpgme_sub_key_t mysk = me->subkeys ; mysk ; mysk = mysk->next) { for (gpgme_sub_key_t hissk = him->subkeys ; hissk ; hissk = hissk->next) { if (strcmp(mysk->fpr, hissk->fpr) == 0) { mysk->is_cardkey |= hissk->is_cardkey; break; } } } return *this; } void Key::update() { + if (isNull() || !primaryFingerprint()) { + return; + } auto ctx = Context::createForProtocol(protocol()); if (!ctx) { return; } ctx->setKeyListMode(KeyListMode::Local | KeyListMode::Signatures | KeyListMode::SignatureNotations | KeyListMode::Validate | KeyListMode::WithTofu); Error err; auto newKey = ctx->key(primaryFingerprint(), err, true); // Not secret so we get the information from the pubring. if (newKey.isNull()) { newKey = ctx->key(primaryFingerprint(), err, false); } delete ctx; if (err) { return; } swap(newKey); return; } // static Key Key::locate(const char *mbox) { if (!mbox) { return Key(); } auto ctx = Context::createForProtocol(OpenPGP); if (!ctx) { return Key(); } ctx->setKeyListMode (Extern | Local); Error e = ctx->startKeyListing (mbox); auto ret = ctx->nextKey (e); delete ctx; return ret; } // // // class Subkey // // gpgme_sub_key_t find_subkey(const shared_gpgme_key_t &key, unsigned int idx) { if (key) { for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next, --idx) { if (idx == 0) { return s; } } } return 0; } gpgme_sub_key_t verify_subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey) { if (key) { for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next) { if (s == subkey) { return subkey; } } } return 0; } Subkey::Subkey() : key(), subkey(0) {} Subkey::Subkey(const shared_gpgme_key_t &k, unsigned int idx) : key(k), subkey(find_subkey(k, idx)) { } Subkey::Subkey(const shared_gpgme_key_t &k, gpgme_sub_key_t sk) : key(k), subkey(verify_subkey(k, sk)) { } Key Subkey::parent() const { return Key(key); } const char *Subkey::keyID() const { return subkey ? subkey->keyid : 0 ; } const char *Subkey::fingerprint() const { return subkey ? subkey->fpr : 0 ; } Subkey::PubkeyAlgo Subkey::publicKeyAlgorithm() const { return subkey ? static_cast(subkey->pubkey_algo) : AlgoUnknown; } const char *Subkey::publicKeyAlgorithmAsString() const { return gpgme_pubkey_algo_name(subkey ? subkey->pubkey_algo : (gpgme_pubkey_algo_t)0); } /* static */ const char *Subkey::publicKeyAlgorithmAsString(PubkeyAlgo algo) { if (algo == AlgoUnknown) { return NULL; } return gpgme_pubkey_algo_name(static_cast(algo)); } std::string Subkey::algoName() const { char *gpgmeStr; if (subkey && (gpgmeStr = gpgme_pubkey_algo_string(subkey))) { std::string ret = std::string(gpgmeStr); gpgme_free(gpgmeStr); return ret; } return std::string(); } bool Subkey::canEncrypt() const { return subkey && subkey->can_encrypt; } bool Subkey::canSign() const { return subkey && subkey->can_sign; } bool Subkey::canCertify() const { return subkey && subkey->can_certify; } bool Subkey::canAuthenticate() const { return subkey && subkey->can_authenticate; } bool Subkey::isQualified() const { return subkey && subkey->is_qualified; } bool Subkey::isDeVs() const { return subkey && subkey->is_de_vs; } bool Subkey::isCardKey() const { return subkey && subkey->is_cardkey; } const char *Subkey::cardSerialNumber() const { return subkey ? subkey->card_number : nullptr; } const char *Subkey::keyGrip() const { return subkey ? subkey->keygrip : nullptr; } bool Subkey::isSecret() const { return subkey && subkey->secret; } unsigned int Subkey::length() const { return subkey ? subkey->length : 0 ; } time_t Subkey::creationTime() const { return static_cast(subkey ? subkey->timestamp : 0); } time_t Subkey::expirationTime() const { return static_cast(subkey ? subkey->expires : 0); } bool Subkey::neverExpires() const { return expirationTime() == time_t(0); } bool Subkey::isRevoked() const { return subkey && subkey->revoked; } bool Subkey::isInvalid() const { return subkey && subkey->invalid; } bool Subkey::isExpired() const { return subkey && subkey->expired; } bool Subkey::isDisabled() const { return subkey && subkey->disabled; } // // // class UserID // // gpgme_user_id_t find_uid(const shared_gpgme_key_t &key, unsigned int idx) { if (key) { for (gpgme_user_id_t u = key->uids ; u ; u = u->next, --idx) { if (idx == 0) { return u; } } } return 0; } gpgme_user_id_t verify_uid(const shared_gpgme_key_t &key, gpgme_user_id_t uid) { if (key) { for (gpgme_user_id_t u = key->uids ; u ; u = u->next) { if (u == uid) { return uid; } } } return 0; } UserID::UserID() : key(), uid(0) {} UserID::UserID(const shared_gpgme_key_t &k, gpgme_user_id_t u) : key(k), uid(verify_uid(k, u)) { } UserID::UserID(const shared_gpgme_key_t &k, unsigned int idx) : key(k), uid(find_uid(k, idx)) { } Key UserID::parent() const { return Key(key); } UserID::Signature UserID::signature(unsigned int index) const { return Signature(key, uid, index); } unsigned int UserID::numSignatures() const { if (!uid) { return 0; } unsigned int count = 0; for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) { ++count; } return count; } std::vector UserID::signatures() const { if (!uid) { return std::vector(); } std::vector v; v.reserve(numSignatures()); for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) { v.push_back(Signature(key, uid, sig)); } return v; } const char *UserID::id() const { return uid ? uid->uid : 0 ; } const char *UserID::name() const { return uid ? uid->name : 0 ; } const char *UserID::email() const { return uid ? uid->email : 0 ; } const char *UserID::comment() const { return uid ? uid->comment : 0 ; } UserID::Validity UserID::validity() const { if (!uid) { return Unknown; } switch (uid->validity) { default: case GPGME_VALIDITY_UNKNOWN: return Unknown; case GPGME_VALIDITY_UNDEFINED: return Undefined; case GPGME_VALIDITY_NEVER: return Never; case GPGME_VALIDITY_MARGINAL: return Marginal; case GPGME_VALIDITY_FULL: return Full; case GPGME_VALIDITY_ULTIMATE: return Ultimate; } } char UserID::validityAsString() const { if (!uid) { return '?'; } switch (uid->validity) { default: case GPGME_VALIDITY_UNKNOWN: return '?'; case GPGME_VALIDITY_UNDEFINED: return 'q'; case GPGME_VALIDITY_NEVER: return 'n'; case GPGME_VALIDITY_MARGINAL: return 'm'; case GPGME_VALIDITY_FULL: return 'f'; case GPGME_VALIDITY_ULTIMATE: return 'u'; } } bool UserID::isRevoked() const { return uid && uid->revoked; } bool UserID::isInvalid() const { return uid && uid->invalid; } TofuInfo UserID::tofuInfo() const { if (!uid) { return TofuInfo(); } return TofuInfo(uid->tofu); } // // // class Signature // // gpgme_key_sig_t find_signature(gpgme_user_id_t uid, unsigned int idx) { if (uid) { for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next, --idx) { if (idx == 0) { return s; } } } return 0; } gpgme_key_sig_t verify_signature(gpgme_user_id_t uid, gpgme_key_sig_t sig) { if (uid) { for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next) { if (s == sig) { return sig; } } } return 0; } UserID::Signature::Signature() : key(), uid(0), sig(0) {} UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, unsigned int idx) : key(k), uid(verify_uid(k, u)), sig(find_signature(uid, idx)) { } UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, gpgme_key_sig_t s) : key(k), uid(verify_uid(k, u)), sig(verify_signature(uid, s)) { } UserID UserID::Signature::parent() const { return UserID(key, uid); } const char *UserID::Signature::signerKeyID() const { return sig ? sig->keyid : 0 ; } const char *UserID::Signature::algorithmAsString() const { return gpgme_pubkey_algo_name(sig ? sig->pubkey_algo : (gpgme_pubkey_algo_t)0); } unsigned int UserID::Signature::algorithm() const { return sig ? sig->pubkey_algo : 0 ; } time_t UserID::Signature::creationTime() const { return static_cast(sig ? sig->timestamp : 0); } time_t UserID::Signature::expirationTime() const { return static_cast(sig ? sig->expires : 0); } bool UserID::Signature::neverExpires() const { return expirationTime() == time_t(0); } bool UserID::Signature::isRevokation() const { return sig && sig->revoked; } bool UserID::Signature::isInvalid() const { return sig && sig->invalid; } bool UserID::Signature::isExpired() const { return sig && sig->expired; } bool UserID::Signature::isExportable() const { return sig && sig->exportable; } const char *UserID::Signature::signerUserID() const { return sig ? sig->uid : 0 ; } const char *UserID::Signature::signerName() const { return sig ? sig->name : 0 ; } const char *UserID::Signature::signerEmail() const { return sig ? sig->email : 0 ; } const char *UserID::Signature::signerComment() const { return sig ? sig->comment : 0 ; } unsigned int UserID::Signature::certClass() const { return sig ? sig->sig_class : 0 ; } UserID::Signature::Status UserID::Signature::status() const { if (!sig) { return GeneralError; } switch (gpgme_err_code(sig->status)) { case GPG_ERR_NO_ERROR: return NoError; case GPG_ERR_SIG_EXPIRED: return SigExpired; case GPG_ERR_KEY_EXPIRED: return KeyExpired; case GPG_ERR_BAD_SIGNATURE: return BadSignature; case GPG_ERR_NO_PUBKEY: return NoPublicKey; default: case GPG_ERR_GENERAL: return GeneralError; } } std::string UserID::Signature::statusAsString() const { if (!sig) { return std::string(); } char buf[ 1024 ]; gpgme_strerror_r(sig->status, buf, sizeof buf); buf[ sizeof buf - 1 ] = '\0'; return std::string(buf); } GpgME::Notation UserID::Signature::notation(unsigned int idx) const { if (!sig) { return GpgME::Notation(); } for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) { if (nota->name) { if (idx-- == 0) { return GpgME::Notation(nota); } } } return GpgME::Notation(); } unsigned int UserID::Signature::numNotations() const { if (!sig) { return 0; } unsigned int count = 0; for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) { if (nota->name) { ++count; // others are policy URLs... } } return count; } std::vector UserID::Signature::notations() const { if (!sig) { return std::vector(); } std::vector v; v.reserve(numNotations()); for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) { if (nota->name) { v.push_back(GpgME::Notation(nota)); } } return v; } const char *UserID::Signature::policyURL() const { if (!sig) { return 0; } for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) { if (!nota->name) { return nota->value; } } return 0; } std::string UserID::addrSpecFromString(const char *userid) { if (!userid) { return std::string(); } char *normalized = gpgme_addrspec_from_uid (userid); if (normalized) { std::string ret(normalized); gpgme_free(normalized); return ret; } return std::string(); } std::string UserID::addrSpec() const { if (!uid || !uid->address) { return std::string(); } return uid->address; } Error UserID::revoke() { if (isNull()) { return Error::fromCode(GPG_ERR_GENERAL); } auto ctx = Context::createForProtocol(parent().protocol()); if (!ctx) { return Error::fromCode(GPG_ERR_INV_ENGINE); } Error ret = ctx->revUid(key, id()); delete ctx; return ret; } static Key::Origin gpgme_origin_to_pp_origin (const unsigned int origin) { switch (origin) { case GPGME_KEYORG_KS: return Key::OriginKS; case GPGME_KEYORG_DANE: return Key::OriginDane; case GPGME_KEYORG_WKD: return Key::OriginWKD; case GPGME_KEYORG_URL: return Key::OriginURL; case GPGME_KEYORG_FILE: return Key::OriginFile; case GPGME_KEYORG_SELF: return Key::OriginSelf; case GPGME_KEYORG_OTHER: return Key::OriginOther; case GPGME_KEYORG_UNKNOWN: default: return Key::OriginUnknown; } } Key::Origin UserID::origin() const { if (isNull()) { return Key::OriginUnknown; } return gpgme_origin_to_pp_origin(uid->origin); } time_t UserID::lastUpdate() const { return static_cast(uid ? uid->last_update : 0); } Error Key::addUid(const char *uid) { if (isNull()) { return Error::fromCode(GPG_ERR_GENERAL); } auto ctx = Context::createForProtocol(protocol()); if (!ctx) { return Error::fromCode(GPG_ERR_INV_ENGINE); } Error ret = ctx->addUid(key, uid); delete ctx; return ret; } Key::Origin Key::origin() const { if (isNull()) { return OriginUnknown; } return gpgme_origin_to_pp_origin(key->origin); } time_t Key::lastUpdate() const { return static_cast(key ? key->last_update : 0); } std::ostream &operator<<(std::ostream &os, const UserID &uid) { os << "GpgME::UserID("; if (!uid.isNull()) { os << "\n name: " << protect(uid.name()) << "\n email: " << protect(uid.email()) << "\n mbox: " << uid.addrSpec() << "\n comment: " << protect(uid.comment()) << "\n validity: " << uid.validityAsString() << "\n revoked: " << uid.isRevoked() << "\n invalid: " << uid.isInvalid() << "\n numsigs: " << uid.numSignatures() << "\n origin: " << uid.origin() << "\n updated: " << uid.lastUpdate() << "\n tofuinfo:\n" << uid.tofuInfo(); } return os << ')'; } std::ostream &operator<<(std::ostream &os, const Key &key) { os << "GpgME::Key("; if (!key.isNull()) { os << "\n protocol: " << protect(key.protocolAsString()) << "\n ownertrust: " << key.ownerTrustAsString() << "\n issuer: " << protect(key.issuerName()) << "\n fingerprint:" << protect(key.primaryFingerprint()) << "\n listmode: " << key.keyListMode() << "\n canSign: " << key.canReallySign() << "\n canEncrypt: " << key.canEncrypt() << "\n canCertify: " << key.canCertify() << "\n canAuth: " << key.canAuthenticate() << "\n origin: " << key.origin() << "\n updated: " << key.lastUpdate() << "\n uids:\n"; const std::vector uids = key.userIDs(); std::copy(uids.begin(), uids.end(), std::ostream_iterator(os, "\n")); } return os << ')'; } } // namespace GpgME diff --git a/lang/cpp/src/verificationresult.cpp b/lang/cpp/src/verificationresult.cpp index 2c42d074..fa8237ad 100644 --- a/lang/cpp/src/verificationresult.cpp +++ b/lang/cpp/src/verificationresult.cpp @@ -1,622 +1,622 @@ /* verificationresult.cpp - wraps a gpgme verify result Copyright (C) 2004 Klarälvdalens Datakonsult AB 2016 Bundesamt für Sicherheit in der Informationstechnik Software engineering by Intevation GmbH This file is part of GPGME++. GPGME++ is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GPGME++ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with GPGME++; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "result_p.h" #include "util.h" #include "key.h" #include "context.h" #include #include #include #include #include #include #include #include class GpgME::VerificationResult::Private { public: explicit Private(const gpgme_verify_result_t r) { if (!r) { return; } if (r->file_name) { file_name = r->file_name; } // copy recursively, using compiler-generated copy ctor. // We just need to handle the pointers in the structs: for (gpgme_signature_t is = r->signatures ; is ; is = is->next) { gpgme_signature_t scopy = new _gpgme_signature(*is); if (is->fpr) { scopy->fpr = strdup(is->fpr); } // PENDING(marc) why does this crash on Windows in strdup()? # ifndef _WIN32 if (is->pka_address) { scopy->pka_address = strdup(is->pka_address); } # else scopy->pka_address = 0; # endif scopy->next = 0; sigs.push_back(scopy); // copy keys if (scopy->key) { keys.push_back(Key(scopy->key, true)); } else { keys.push_back(Key()); } // copy notations: nota.push_back(std::vector()); purls.push_back(0); for (gpgme_sig_notation_t in = is->notations ; in ; in = in->next) { if (!in->name) { if (in->value) { purls.back() = strdup(in->value); // policy url } continue; } Nota n = { 0, 0, in->flags }; n.name = strdup(in->name); if (in->value) { n.value = strdup(in->value); } nota.back().push_back(n); } } } ~Private() { for (std::vector::iterator it = sigs.begin() ; it != sigs.end() ; ++it) { std::free((*it)->fpr); std::free((*it)->pka_address); delete *it; *it = 0; } for (std::vector< std::vector >::iterator it = nota.begin() ; it != nota.end() ; ++it) { for (std::vector::iterator jt = it->begin() ; jt != it->end() ; ++jt) { std::free(jt->name); jt->name = 0; std::free(jt->value); jt->value = 0; } } std::for_each(purls.begin(), purls.end(), &std::free); } struct Nota { char *name; char *value; gpgme_sig_notation_flags_t flags; }; std::vector sigs; std::vector< std::vector > nota; std::vector keys; std::vector purls; std::string file_name; Protocol proto; }; GpgME::VerificationResult::VerificationResult(gpgme_ctx_t ctx, int error) : GpgME::Result(error), d() { init(ctx); } GpgME::VerificationResult::VerificationResult(gpgme_ctx_t ctx, const Error &error) : GpgME::Result(error), d() { init(ctx); } void GpgME::VerificationResult::init(gpgme_ctx_t ctx) { if (!ctx) { return; } gpgme_verify_result_t res = gpgme_op_verify_result(ctx); if (!res) { return; } d.reset(new Private(res)); gpgme_protocol_t proto = gpgme_get_protocol(ctx); d->proto = proto == GPGME_PROTOCOL_OpenPGP ? OpenPGP : proto == GPGME_PROTOCOL_CMS ? CMS : UnknownProtocol; } make_standard_stuff(VerificationResult) const char *GpgME::VerificationResult::fileName() const { return d ? d->file_name.c_str() : 0 ; } unsigned int GpgME::VerificationResult::numSignatures() const { return d ? d->sigs.size() : 0 ; } GpgME::Signature GpgME::VerificationResult::signature(unsigned int idx) const { return Signature(d, idx); } std::vector GpgME::VerificationResult::signatures() const { if (!d) { return std::vector(); } std::vector result; result.reserve(d->sigs.size()); for (unsigned int i = 0 ; i < d->sigs.size() ; ++i) { result.push_back(Signature(d, i)); } return result; } GpgME::Signature::Signature(const std::shared_ptr &parent, unsigned int i) : d(parent), idx(i) { } GpgME::Signature::Signature() : d(), idx(0) {} bool GpgME::Signature::isNull() const { return !d || idx >= d->sigs.size() ; } GpgME::Signature::Summary GpgME::Signature::summary() const { if (isNull()) { return None; } gpgme_sigsum_t sigsum = d->sigs[idx]->summary; unsigned int result = 0; if (sigsum & GPGME_SIGSUM_VALID) { result |= Valid; } if (sigsum & GPGME_SIGSUM_GREEN) { result |= Green; } if (sigsum & GPGME_SIGSUM_RED) { result |= Red; } if (sigsum & GPGME_SIGSUM_KEY_REVOKED) { result |= KeyRevoked; } if (sigsum & GPGME_SIGSUM_KEY_EXPIRED) { result |= KeyExpired; } if (sigsum & GPGME_SIGSUM_SIG_EXPIRED) { result |= SigExpired; } if (sigsum & GPGME_SIGSUM_KEY_MISSING) { result |= KeyMissing; } if (sigsum & GPGME_SIGSUM_CRL_MISSING) { result |= CrlMissing; } if (sigsum & GPGME_SIGSUM_CRL_TOO_OLD) { result |= CrlTooOld; } if (sigsum & GPGME_SIGSUM_BAD_POLICY) { result |= BadPolicy; } if (sigsum & GPGME_SIGSUM_SYS_ERROR) { result |= SysError; } if (sigsum & GPGME_SIGSUM_TOFU_CONFLICT) { result |= TofuConflict; } return static_cast(result); } const char *GpgME::Signature::fingerprint() const { return isNull() ? 0 : d->sigs[idx]->fpr ; } GpgME::Error GpgME::Signature::status() const { return Error(isNull() ? 0 : d->sigs[idx]->status); } time_t GpgME::Signature::creationTime() const { return static_cast(isNull() ? 0 : d->sigs[idx]->timestamp); } time_t GpgME::Signature::expirationTime() const { return static_cast(isNull() ? 0 : d->sigs[idx]->exp_timestamp); } bool GpgME::Signature::neverExpires() const { return expirationTime() == (time_t)0; } bool GpgME::Signature::isWrongKeyUsage() const { return !isNull() && d->sigs[idx]->wrong_key_usage; } bool GpgME::Signature::isVerifiedUsingChainModel() const { return !isNull() && d->sigs[idx]->chain_model; } bool GpgME::Signature::isDeVs() const { return !isNull() && d->sigs[idx]->is_de_vs; } GpgME::Signature::PKAStatus GpgME::Signature::pkaStatus() const { if (!isNull()) { return static_cast(d->sigs[idx]->pka_trust); } return UnknownPKAStatus; } const char *GpgME::Signature::pkaAddress() const { if (!isNull()) { return d->sigs[idx]->pka_address; } return 0; } GpgME::Signature::Validity GpgME::Signature::validity() const { if (isNull()) { return Unknown; } switch (d->sigs[idx]->validity) { default: case GPGME_VALIDITY_UNKNOWN: return Unknown; case GPGME_VALIDITY_UNDEFINED: return Undefined; case GPGME_VALIDITY_NEVER: return Never; case GPGME_VALIDITY_MARGINAL: return Marginal; case GPGME_VALIDITY_FULL: return Full; case GPGME_VALIDITY_ULTIMATE: return Ultimate; } } char GpgME::Signature::validityAsString() const { if (isNull()) { return '?'; } switch (d->sigs[idx]->validity) { default: case GPGME_VALIDITY_UNKNOWN: return '?'; case GPGME_VALIDITY_UNDEFINED: return 'q'; case GPGME_VALIDITY_NEVER: return 'n'; case GPGME_VALIDITY_MARGINAL: return 'm'; case GPGME_VALIDITY_FULL: return 'f'; case GPGME_VALIDITY_ULTIMATE: return 'u'; } } GpgME::Error GpgME::Signature::nonValidityReason() const { return Error(isNull() ? 0 : d->sigs[idx]->validity_reason); } unsigned int GpgME::Signature::publicKeyAlgorithm() const { if (!isNull()) { return d->sigs[idx]->pubkey_algo; } return 0; } const char *GpgME::Signature::publicKeyAlgorithmAsString() const { if (!isNull()) { return gpgme_pubkey_algo_name(d->sigs[idx]->pubkey_algo); } return 0; } unsigned int GpgME::Signature::hashAlgorithm() const { if (!isNull()) { return d->sigs[idx]->hash_algo; } return 0; } const char *GpgME::Signature::hashAlgorithmAsString() const { if (!isNull()) { return gpgme_hash_algo_name(d->sigs[idx]->hash_algo); } return 0; } const char *GpgME::Signature::policyURL() const { return isNull() ? 0 : d->purls[idx] ; } GpgME::Notation GpgME::Signature::notation(unsigned int nidx) const { return GpgME::Notation(d, idx, nidx); } std::vector GpgME::Signature::notations() const { if (isNull()) { return std::vector(); } std::vector result; result.reserve(d->nota[idx].size()); for (unsigned int i = 0 ; i < d->nota[idx].size() ; ++i) { result.push_back(GpgME::Notation(d, idx, i)); } return result; } GpgME::Key GpgME::Signature::key() const { if (isNull()) { return Key(); } return d->keys[idx]; } GpgME::Key GpgME::Signature::key(bool search, bool update) const { if (isNull()) { return Key(); } GpgME::Key ret = key(); - if (ret.isNull() && search) { + if (ret.isNull() && search && fingerprint ()) { auto ctx = Context::createForProtocol (d->proto); if (ctx) { ctx->setKeyListMode(KeyListMode::Local | KeyListMode::Signatures | KeyListMode::SignatureNotations | KeyListMode::Validate | KeyListMode::WithTofu); Error e; ret = d->keys[idx] = ctx->key(fingerprint(), e, false); delete ctx; } } if (update) { d->keys[idx].update(); ret = d->keys[idx]; } return ret; } class GpgME::Notation::Private { public: Private() : d(), sidx(0), nidx(0), nota(0) {} Private(const std::shared_ptr &priv, unsigned int sindex, unsigned int nindex) : d(priv), sidx(sindex), nidx(nindex), nota(0) { } Private(gpgme_sig_notation_t n) : d(), sidx(0), nidx(0), nota(n ? new _gpgme_sig_notation(*n) : 0) { if (nota && nota->name) { nota->name = strdup(nota->name); } if (nota && nota->value) { nota->value = strdup(nota->value); } } Private(const Private &other) : d(other.d), sidx(other.sidx), nidx(other.nidx), nota(other.nota) { if (nota) { nota->name = strdup(nota->name); nota->value = strdup(nota->value); } } ~Private() { if (nota) { std::free(nota->name); nota->name = 0; std::free(nota->value); nota->value = 0; delete nota; } } std::shared_ptr d; unsigned int sidx, nidx; gpgme_sig_notation_t nota; }; GpgME::Notation::Notation(const std::shared_ptr &parent, unsigned int sindex, unsigned int nindex) : d(new Private(parent, sindex, nindex)) { } GpgME::Notation::Notation(gpgme_sig_notation_t nota) : d(new Private(nota)) { } GpgME::Notation::Notation() : d() {} bool GpgME::Notation::isNull() const { if (!d) { return true; } if (d->d) { return d->sidx >= d->d->nota.size() || d->nidx >= d->d->nota[d->sidx].size() ; } return !d->nota; } const char *GpgME::Notation::name() const { return isNull() ? 0 : d->d ? d->d->nota[d->sidx][d->nidx].name : d->nota ? d->nota->name : 0 ; } const char *GpgME::Notation::value() const { return isNull() ? 0 : d->d ? d->d->nota[d->sidx][d->nidx].value : d->nota ? d->nota->value : 0 ; } GpgME::Notation::Flags GpgME::Notation::flags() const { return convert_from_gpgme_sig_notation_flags_t( isNull() ? 0 : d->d ? d->d->nota[d->sidx][d->nidx].flags : d->nota ? d->nota->flags : 0); } bool GpgME::Notation::isHumanReadable() const { return flags() & HumanReadable; } bool GpgME::Notation::isCritical() const { return flags() & Critical; } std::ostream &GpgME::operator<<(std::ostream &os, const VerificationResult &result) { os << "GpgME::VerificationResult("; if (!result.isNull()) { os << "\n error: " << result.error() << "\n fileName: " << protect(result.fileName()) << "\n signatures:\n"; const std::vector sigs = result.signatures(); std::copy(sigs.begin(), sigs.end(), std::ostream_iterator(os, "\n")); } return os << ')'; } std::ostream &GpgME::operator<<(std::ostream &os, Signature::PKAStatus pkaStatus) { #define OUTPUT( x ) if ( !(pkaStatus & (GpgME::Signature:: x)) ) {} else do { os << #x " "; } while(0) os << "GpgME::Signature::PKAStatus("; OUTPUT(UnknownPKAStatus); OUTPUT(PKAVerificationFailed); OUTPUT(PKAVerificationSucceeded); #undef OUTPUT return os << ')'; } std::ostream &GpgME::operator<<(std::ostream &os, Signature::Summary summary) { #define OUTPUT( x ) if ( !(summary & (GpgME::Signature:: x)) ) {} else do { os << #x " "; } while(0) os << "GpgME::Signature::Summary("; OUTPUT(Valid); OUTPUT(Green); OUTPUT(Red); OUTPUT(KeyRevoked); OUTPUT(KeyExpired); OUTPUT(SigExpired); OUTPUT(KeyMissing); OUTPUT(CrlMissing); OUTPUT(CrlTooOld); OUTPUT(BadPolicy); OUTPUT(SysError); OUTPUT(TofuConflict); #undef OUTPUT return os << ')'; } std::ostream &GpgME::operator<<(std::ostream &os, const Signature &sig) { os << "GpgME::Signature("; if (!sig.isNull()) { os << "\n Summary: " << sig.summary() << "\n Fingerprint: " << protect(sig.fingerprint()) << "\n Status: " << sig.status() << "\n creationTime: " << sig.creationTime() << "\n expirationTime: " << sig.expirationTime() << "\n isWrongKeyUsage: " << sig.isWrongKeyUsage() << "\n isVerifiedUsingChainModel: " << sig.isVerifiedUsingChainModel() << "\n pkaStatus: " << sig.pkaStatus() << "\n pkaAddress: " << protect(sig.pkaAddress()) << "\n validity: " << sig.validityAsString() << "\n nonValidityReason: " << sig.nonValidityReason() << "\n publicKeyAlgorithm: " << protect(sig.publicKeyAlgorithmAsString()) << "\n hashAlgorithm: " << protect(sig.hashAlgorithmAsString()) << "\n policyURL: " << protect(sig.policyURL()) << "\n isDeVs " << sig.isDeVs() << "\n notations:\n"; const std::vector nota = sig.notations(); std::copy(nota.begin(), nota.end(), std::ostream_iterator(os, "\n")); } return os << ')'; } std::ostream &GpgME::operator<<(std::ostream &os, Notation::Flags flags) { os << "GpgME::Notation::Flags("; #define OUTPUT( x ) if ( !(flags & (GpgME::Notation:: x)) ) {} else do { os << #x " "; } while(0) OUTPUT(HumanReadable); OUTPUT(Critical); #undef OUTPUT return os << ')'; } std::ostream &GpgME::operator<<(std::ostream &os, const Notation ¬a) { os << "GpgME::Signature::Notation("; if (!nota.isNull()) { os << "\n name: " << protect(nota.name()) << "\n value: " << protect(nota.value()) << "\n flags: " << nota.flags() << '\n'; } return os << ")"; }