Page MenuHome GnuPG

No OneTemporary

diff --git a/src/key.cpp b/src/key.cpp
index e536d080..f9cc2b60 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -1,1264 +1,1270 @@
/*
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 <key.h>
#include "util.h"
#include "tofuinfo.h"
#include "context.h"
#include "engineinfo.h"
#include <gpgme.h>
#include <string.h>
#include <strings.h>
#include <cassert>
#include <istream>
#include <iterator>
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<UserID> Key::userIDs() const
{
if (!key) {
return std::vector<UserID>();
}
std::vector<UserID> 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<Subkey> Key::subkeys() const
{
if (!key) {
return std::vector<Subkey>();
}
std::vector<Subkey> 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) : nullptr ;
}
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 : nullptr ;
}
const char *Key::issuerName() const
{
return key ? key->issuer_name : nullptr ;
}
const char *Key::chainID() const
{
return key ? key->chain_id : nullptr ;
}
const char *Key::keyID() const
{
return key && key->subkeys ? key->subkeys->keyid : nullptr ;
}
const char *Key::shortKeyID() const
{
if (!key || !key->subkeys || !key->subkeys->keyid) {
return nullptr;
}
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;
mysk->secret |= hissk->secret;
if (hissk->keygrip && !mysk->keygrip) {
mysk->keygrip = strdup(hissk->keygrip);
}
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 |
KeyListMode::WithKeygrip |
KeyListMode::WithSecret);
Error err;
Key newKey;
if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.1.0") {
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);
}
} else {
newKey = ctx->key(primaryFingerprint(), err, false);
}
delete ctx;
if (err) {
return;
}
swap(newKey);
}
// 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
//
//
static 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 nullptr;
}
static 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 nullptr;
}
Subkey::Subkey() : key(), subkey(nullptr) {}
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 : nullptr ;
}
const char *Subkey::fingerprint() const
{
return subkey ? subkey->fpr : nullptr ;
}
Subkey::PubkeyAlgo Subkey::publicKeyAlgorithm() const
{
return subkey ? static_cast<PubkeyAlgo>(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<gpgme_pubkey_algo_t>(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<time_t>(subkey ? subkey->timestamp : 0);
}
time_t Subkey::expirationTime() const
{
return static_cast<time_t>(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
//
//
static 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 nullptr;
}
static 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 nullptr;
}
UserID::UserID() : key(), uid(nullptr) {}
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::Signature> UserID::signatures() const
{
if (!uid) {
return std::vector<Signature>();
}
std::vector<Signature> 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 : nullptr ;
}
const char *UserID::name() const
{
return uid ? uid->name : nullptr ;
}
const char *UserID::email() const
{
return uid ? uid->email : nullptr ;
}
const char *UserID::comment() const
{
return uid ? uid->comment : nullptr ;
}
const char *UserID::uidhash() const
{
return uid ? uid->uidhash : nullptr ;
}
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);
}
static gpgme_key_sig_t find_last_valid_sig_for_keyid (gpgme_user_id_t uid,
const char *keyid)
{
if (!keyid) {
return nullptr;
}
gpgme_key_sig_t ret = NULL;
for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next) {
if (s->keyid && !strcmp(keyid, s->keyid)) {
if (!s->expired && !s->revoked && !s->invalid && !s->status) {
if (!ret) {
ret = s;
} else if (ret && ret->timestamp <= s->timestamp) {
/* Equals because when the timestamps are the same we prefer
the last in the list */
ret = s;
}
}
}
}
return ret;
}
const char *UserID::remark(const Key &remarker, Error &err) const
{
if (!uid || remarker.isNull()) {
err = Error::fromCode(GPG_ERR_GENERAL);
return nullptr;
}
if (key->protocol != GPGME_PROTOCOL_OpenPGP) {
return nullptr;
}
if (!(key->keylist_mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS) ||
!(key->keylist_mode & GPGME_KEYLIST_MODE_SIGS)) {
err = Error::fromCode(GPG_ERR_NO_DATA);
return nullptr;
}
gpgme_key_sig_t s = find_last_valid_sig_for_keyid(uid, remarker.keyID());
if (!s) {
return nullptr;
}
for (gpgme_sig_notation_t n = s->notations; n ; n = n->next) {
if (n->name && !strcmp(n->name, "rem@gnupg.org")) {
return n->value;
}
}
return nullptr;
}
std::vector<std::string> UserID::remarks(std::vector<Key> keys, Error &err) const
{
std::vector<std::string> ret;
for (const auto &key: keys) {
const char *rem = remark(key, err);
if (err) {
return ret;
}
if (rem) {
ret.push_back(rem);
}
}
return ret;
}
//
//
// class Signature
//
//
static 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 nullptr;
}
static 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 nullptr;
}
static int signature_index(gpgme_user_id_t uid, gpgme_key_sig_t sig)
{
if (uid) {
int i = 0;
for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next, ++i) {
if (s == sig) {
return i;
}
}
}
return -1;
}
UserID::Signature::Signature() : key(), uid(nullptr), sig(nullptr) {}
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))
{
}
bool UserID::Signature::operator<(const Signature &other)
+{
+ // kept for binary compatibility
+ return static_cast<const UserID::Signature *>(this)->operator<(other);
+}
+
+bool UserID::Signature::operator<(const Signature &other) const
{
// based on cmp_signodes() in g10/keylist.c
// both signatures must belong to the same user ID
assert(uid == other.uid);
// self-signatures are ordered first
const char *primaryKeyId = parent().parent().keyID();
const bool thisIsSelfSignature = strcmp(signerKeyID(), primaryKeyId) == 0;
const bool otherIsSelfSignature = strcmp(other.signerKeyID(), primaryKeyId) == 0;
if (thisIsSelfSignature && !otherIsSelfSignature) {
return true;
}
if (otherIsSelfSignature && !thisIsSelfSignature) {
return false;
}
// then sort by signer key ID (which are or course the same for self-sigs)
const int keyIdComparison = strcmp(signerKeyID(), other.signerKeyID());
if (keyIdComparison < 0) {
return true;
}
if (keyIdComparison > 0) {
return false;
}
// followed by creation time
if (creationTime() < other.creationTime()) {
return true;
}
if (creationTime() > other.creationTime()) {
return false;
}
// followed by the class in a way that a rev comes first
if (certClass() < other.certClass()) {
return true;
}
if (certClass() > other.certClass()) {
return false;
}
// to make the sort stable we compare the indexes of the signatures as last resort
return signature_index(uid, sig) < signature_index(uid, other.sig);
}
UserID UserID::Signature::parent() const
{
return UserID(key, uid);
}
const char *UserID::Signature::signerKeyID() const
{
return sig ? sig->keyid : nullptr ;
}
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<time_t>(sig ? sig->timestamp : 0);
}
time_t UserID::Signature::expirationTime() const
{
return static_cast<time_t>(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 : nullptr ;
}
const char *UserID::Signature::signerName() const
{
return sig ? sig->name : nullptr ;
}
const char *UserID::Signature::signerEmail() const
{
return sig ? sig->email : nullptr ;
}
const char *UserID::Signature::signerComment() const
{
return sig ? sig->comment : nullptr ;
}
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<Notation> UserID::Signature::notations() const
{
if (!sig) {
return std::vector<GpgME::Notation>();
}
std::vector<GpgME::Notation> 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 nullptr;
}
for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
if (!nota->name) {
return nota->value;
}
}
return nullptr;
}
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<time_t>(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<time_t>(key ? key->last_update : 0);
}
bool Key::isBad() const
{
return isNull() || isRevoked() || isExpired() || isDisabled() || isInvalid();
}
bool Subkey::isBad() const
{
return isNull() || isRevoked() || isExpired() || isDisabled() || isInvalid();
}
bool UserID::isBad() const
{
return isNull() || isRevoked() || isInvalid();
}
bool UserID::Signature::isBad() const
{
return isNull() || isExpired() || isInvalid();
}
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 Subkey &subkey)
{
os << "GpgME::Subkey(";
if (!subkey.isNull()) {
os << "\n fingerprint: " << protect(subkey.fingerprint())
<< "\n creationTime: " << subkey.creationTime()
<< "\n expirationTime:" << subkey.expirationTime()
<< "\n isRevoked: " << subkey.isRevoked()
<< "\n isExpired: " << subkey.isExpired()
<< "\n isInvalid: " << subkey.isRevoked()
<< "\n isDisabled: " << subkey.isInvalid()
<< "\n canSign: " << subkey.canSign()
<< "\n canEncrypt: " << subkey.canEncrypt()
<< "\n canCertify: " << subkey.canCertify()
<< "\n canAuth: " << subkey.canAuthenticate();
}
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<UserID> uids = key.userIDs();
std::copy(uids.begin(), uids.end(),
std::ostream_iterator<UserID>(os, "\n"));
const std::vector<Subkey> subkeys = key.subkeys();
std::copy(subkeys.begin(), subkeys.end(),
std::ostream_iterator<Subkey>(os, "\n"));
}
return os << ')';
}
} // namespace GpgME
diff --git a/src/key.h b/src/key.h
index a7931672..515bf185 100644
--- a/src/key.h
+++ b/src/key.h
@@ -1,537 +1,539 @@
/*
key.h - 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.
*/
// -*- c++ -*-
#ifndef __GPGMEPP_KEY_H__
#define __GPGMEPP_KEY_H__
#include "global.h"
#include "notation.h"
#include "gpgmefw.h"
#include <memory>
#include <sys/time.h>
#include <vector>
#include <algorithm>
#include <string>
namespace GpgME
{
class Context;
class Subkey;
class UserID;
class TofuInfo;
typedef std::shared_ptr< std::remove_pointer<gpgme_key_t>::type > shared_gpgme_key_t;
//
// class Key
//
class GPGMEPP_EXPORT Key
{
friend class ::GpgME::Context;
struct Null {
Null() {}
};
public:
Key();
/* implicit */ Key(const Null &);
Key(const shared_gpgme_key_t &key);
Key(gpgme_key_t key, bool acquireRef);
static const Null null;
const Key &operator=(Key other)
{
swap(other);
return *this;
}
const Key &mergeWith(const Key &other);
void swap(Key &other)
{
using std::swap;
swap(this->key, other.key);
}
bool isNull() const
{
return !key;
}
UserID userID(unsigned int index) const;
Subkey subkey(unsigned int index) const;
unsigned int numUserIDs() const;
unsigned int numSubkeys() const;
std::vector<UserID> userIDs() const;
std::vector<Subkey> subkeys() const;
bool isRevoked() const;
bool isExpired() const;
bool isDisabled() const;
bool isInvalid() const;
/*! Shorthand for isNull || isRevoked || isExpired ||
* isDisabled || isInvalid */
bool isBad() const;
bool canEncrypt() const;
/*!
This function contains a workaround for old gpgme's: all secret
OpenPGP keys canSign() == true, which canReallySign() doesn't
have. I don't have time to find what breaks when I remove this
workaround, but since Kleopatra merges secret into public keys,
the workaround is not necessary there (and actively harms), I've
added a new function instead.
*/
bool canSign() const;
bool canReallySign() const;
bool canCertify() const;
bool canAuthenticate() const;
bool isQualified() const;
bool isDeVs() const;
bool hasSecret() const;
GPGMEPP_DEPRECATED bool isSecret() const
{
return hasSecret();
}
/*!
@return true if this is a X.509 root certificate (currently
equivalent to something like
strcmp( chainID(), subkey(0).fingerprint() ) == 0 )
*/
bool isRoot() const;
enum OwnerTrust { Unknown = 0, Undefined = 1, Never = 2,
Marginal = 3, Full = 4, Ultimate = 5
};
OwnerTrust ownerTrust() const;
char ownerTrustAsString() const;
Protocol protocol() const;
const char *protocolAsString() const;
const char *issuerSerial() const;
const char *issuerName() const;
const char *chainID() const;
const char *keyID() const;
const char *shortKeyID() const;
const char *primaryFingerprint() const;
unsigned int keyListMode() const;
/*! Update information about this key.
* Starts a keylisting for this key with validity
* and tofu information gathering. Blocks for
* how long the keylisting takes.*/
void update();
/**
* @brief Add a user id to this key.
*
* Needs gnupg 2.1.13 and the key needs to be updated
* afterwards to see the new uid.
*
* @param uid should be fully formatted and UTF-8 encoded.
*
* @returns a possible error.
**/
Error addUid(const char *uid);
/**
* @brief try to locate the best pgp key for a given mailbox.
*
* Boils down to gpg --locate-key <mbox>
* This may take some time if remote sources are also
* used.
*
* @param mbox should be a mail address does not need to be normalized.
*
* @returns The best key for a mailbox or a null key.
*/
static Key locate(const char *mbox);
/* @enum Origin
* @brief The Origin of the key. */
enum Origin : unsigned int {
OriginUnknown = 0,
OriginKS = 1,
OriginDane = 3,
OriginWKD = 4,
OriginURL = 5,
OriginFile = 6,
OriginSelf = 7,
OriginOther = 31,
};
/*! Get the origin of the key.
*
* @returns the Origin. */
Origin origin() const;
/*! Get the last update time.
*
* @returns the last update time. */
time_t lastUpdate() const;
private:
gpgme_key_t impl() const
{
return key.get();
}
shared_gpgme_key_t key;
};
//
// class Subkey
//
class GPGMEPP_EXPORT Subkey
{
public:
Subkey();
Subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey);
Subkey(const shared_gpgme_key_t &key, unsigned int idx);
const Subkey &operator=(Subkey other)
{
swap(other);
return *this;
}
void swap(Subkey &other)
{
using std::swap;
swap(this->key, other.key);
swap(this->subkey, other.subkey);
}
bool isNull() const
{
return !key || !subkey;
}
Key parent() const;
const char *keyID() const;
const char *fingerprint() const;
time_t creationTime() const;
time_t expirationTime() const;
bool neverExpires() const;
bool isRevoked() const;
bool isExpired() const;
bool isInvalid() const;
bool isDisabled() const;
/*! Shorthand for isNull || isRevoked || isExpired ||
* isDisabled || isInvalid */
bool isBad() const;
bool canEncrypt() const;
bool canSign() const;
bool canCertify() const;
bool canAuthenticate() const;
bool isQualified() const;
bool isDeVs() const;
bool isCardKey() const;
bool isSecret() const;
/** Same as gpgme_pubkey_algo_t */
enum PubkeyAlgo {
AlgoUnknown = 0,
AlgoRSA = 1,
AlgoRSA_E = 2,
AlgoRSA_S = 3,
AlgoELG_E = 16,
AlgoDSA = 17,
AlgoECC = 18,
AlgoELG = 20,
AlgoECDSA = 301,
AlgoECDH = 302,
AlgoEDDSA = 303,
AlgoMax = 1 << 31
};
PubkeyAlgo publicKeyAlgorithm() const;
/**
@brief Get the public key algorithm name.
This only works for the pre 2.1 algorithms for ECC NULL is returned.
@returns a statically allocated string with the name of the public
key algorithm, or NULL if that name is not known.
*/
const char *publicKeyAlgorithmAsString() const;
/** @brief Same as publicKeyAlgorithmAsString but static. */
static const char *publicKeyAlgorithmAsString(PubkeyAlgo algo);
/**
@brief Get the key algo string like GnuPG 2.1 prints it.
This returns combinations of size and algorithm. Like
bp512 or rsa2048. Misnamed because publicKeyAlgorithmAsString
already used the older pubkey_algo_name.
Actually uses gpgme_pubkey_algo_string.
@returns the key algorithm as string. Empty string on error.
*/
std::string algoName() const;
unsigned int length() const;
const char *cardSerialNumber() const;
const char *keyGrip() const;
private:
shared_gpgme_key_t key;
gpgme_sub_key_t subkey;
};
//
// class UserID
//
class GPGMEPP_EXPORT UserID
{
public:
class Signature;
UserID();
UserID(const shared_gpgme_key_t &key, gpgme_user_id_t uid);
UserID(const shared_gpgme_key_t &key, unsigned int idx);
const UserID &operator=(UserID other)
{
swap(other);
return *this;
}
void swap(UserID &other)
{
using std::swap;
swap(this->key, other.key);
swap(this->uid, other.uid);
}
bool isNull() const
{
return !key || !uid;
}
Key parent() const;
unsigned int numSignatures() const;
Signature signature(unsigned int index) const;
std::vector<Signature> signatures() const;
const char *id() const;
const char *name() const;
const char *email() const;
const char *comment() const;
const char *uidhash() const;
enum Validity { Unknown = 0, Undefined = 1, Never = 2,
Marginal = 3, Full = 4, Ultimate = 5
};
Validity validity() const;
char validityAsString() const;
bool isRevoked() const;
bool isInvalid() const;
/*! Shorthand for isNull || isRevoked || isInvalid */
bool isBad() const;
/** TOFU info for this userid.
* @returns The TOFU stats or a null TofuInfo.
*/
GpgME::TofuInfo tofuInfo() const;
/*! Wrapper around gpgme_addrspec_from_uid.
*
* The input string should match the format of
* a user id string.
*
* @returns a normalized mail address if found
* or an empty string. */
static std::string addrSpecFromString(const char *uid);
/*! Wrapper around gpgme_addrspec_from_uid.
*
* @returns a normalized mail address for this userid
* or an empty string. */
std::string addrSpec() const;
/*! Revoke the user id.
*
* Key needs update afterwards.
*
* @returns an error on error.*/
Error revoke();
/*! Get the origin of the key.
*
* @returns the Origin. */
Key::Origin origin() const;
/*! Get the last update time.
*
* @returns the last update time. */
time_t lastUpdate() const;
/*! Get a remark made by the key provided.
* A remark is a signature notation on
* this user id made by the key with the
* name "rem@gnupg.org". Returns an error if the
* parent key of this user id was not listed with the
* keylist mode flags for signatures and signature notations.
*
* @param key The key for which comments should be searched.
* @param error Set to GPG_ERR_NO_DATA if the keylist did
* not include signature notations.
*
* @returns The value of the comment or NULL if none exists.
**/
const char *remark(const Key &key,
Error &error) const;
/*! Get multiple remarks made by potentially multiple keys. */
std::vector <std::string> remarks(std::vector<GpgME::Key> remarkers,
Error &error) const;
private:
shared_gpgme_key_t key;
gpgme_user_id_t uid;
};
//
// class UserID::Signature
//
class GPGMEPP_EXPORT UserID::Signature
{
public:
typedef GPGMEPP_DEPRECATED GpgME::Notation Notation;
Signature();
Signature(const shared_gpgme_key_t &key, gpgme_user_id_t uid, gpgme_key_sig_t sig);
Signature(const shared_gpgme_key_t &key, gpgme_user_id_t uid, unsigned int idx);
const Signature &operator=(Signature other)
{
swap(other);
return *this;
}
void swap(Signature &other)
{
using std::swap;
swap(this->key, other.key);
swap(this->uid, other.uid);
swap(this->sig, other.sig);
}
/*! Defines a canonical sort order for signatures of the same user ID. */
- bool operator<(const Signature &other);
+ bool operator<(const Signature &other) const;
+
+ GPGMEPP_DEPRECATED bool operator<(const Signature &other);
bool isNull() const
{
return !sig || !uid || !key ;
}
UserID parent() const;
const char *signerKeyID() const;
const char *algorithmAsString() const;
unsigned int algorithm() const;
time_t creationTime() const;
time_t expirationTime() const;
bool neverExpires() const;
bool isRevokation() const;
bool isInvalid() const;
bool isExpired() const;
bool isExportable() const;
/*! Shorthand for isNull || isExpired || isInvalid */
bool isBad() const;
const char *signerUserID() const;
const char *signerName() const;
const char *signerEmail() const;
const char *signerComment() const;
unsigned int certClass() const;
enum Status { NoError = 0, SigExpired, KeyExpired,
BadSignature, NoPublicKey, GeneralError
};
Status status() const;
std::string statusAsString() const;
const char *policyURL() const;
unsigned int numNotations() const;
GpgME::Notation notation(unsigned int idx) const;
std::vector<GpgME::Notation> notations() const;
private:
shared_gpgme_key_t key;
gpgme_user_id_t uid;
gpgme_key_sig_t sig;
};
GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const UserID &uid);
GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Subkey &subkey);
GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Key &key);
} // namespace GpgME
GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Key)
GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Subkey)
GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(UserID)
GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(UserID::Signature)
GPGMEPP_MAKE_STRCMP(ByFingerprint, .primaryFingerprint());
GPGMEPP_MAKE_STRCMP(ByKeyID, .keyID());
GPGMEPP_MAKE_STRCMP(ByShortKeyID, .shortKeyID());
GPGMEPP_MAKE_STRCMP(ByChainID, .chainID());
#endif // __GPGMEPP_KEY_H__

File Metadata

Mime Type
text/x-diff
Expires
Sun, Dec 14, 3:02 PM (1 d, 19 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
f7/28/ac97289f5c69fd71bb196a69b56f

Event Timeline