"Fossies" - the Fresh Open Source Software Archive

Member "gpgme-1.15.1/lang/cpp/src/key.cpp" (8 Jan 2021, 29660 Bytes) of package /linux/privat/gpgme-1.15.1.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "key.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.15.0_vs_1.15.1.

    1 /*
    2   key.cpp - wraps a gpgme key
    3   Copyright (C) 2003, 2005 Klarälvdalens Datakonsult AB
    4 
    5   This file is part of GPGME++.
    6 
    7   GPGME++ is free software; you can redistribute it and/or
    8   modify it under the terms of the GNU Library General Public
    9   License as published by the Free Software Foundation; either
   10   version 2 of the License, or (at your option) any later version.
   11 
   12   GPGME++ is distributed in the hope that it will be useful,
   13   but WITHOUT ANY WARRANTY; without even the implied warranty of
   14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15   GNU Library General Public License for more details.
   16 
   17   You should have received a copy of the GNU Library General Public License
   18   along with GPGME++; see the file COPYING.LIB.  If not, write to the
   19   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   20   Boston, MA 02110-1301, USA.
   21 */
   22 
   23 #ifdef HAVE_CONFIG_H
   24  #include "config.h"
   25 #endif
   26 
   27 #include <key.h>
   28 
   29 #include "util.h"
   30 #include "tofuinfo.h"
   31 #include "context.h"
   32 #include "engineinfo.h"
   33 
   34 #include <gpgme.h>
   35 
   36 #include <string.h>
   37 #include <strings.h>
   38 #include <cassert>
   39 #include <istream>
   40 #include <iterator>
   41 
   42 const GpgME::Key::Null GpgME::Key::null;
   43 
   44 namespace GpgME
   45 {
   46 
   47 Key::Key() : key() {}
   48 
   49 Key::Key(const Null &) : key() {}
   50 
   51 Key::Key(const shared_gpgme_key_t &k) : key(k) {}
   52 
   53 Key::Key(gpgme_key_t k, bool ref)
   54     : key(k
   55           ? shared_gpgme_key_t(k, &gpgme_key_unref)
   56           : shared_gpgme_key_t())
   57 {
   58     if (ref && impl()) {
   59         gpgme_key_ref(impl());
   60     }
   61 }
   62 
   63 UserID Key::userID(unsigned int index) const
   64 {
   65     return UserID(key, index);
   66 }
   67 
   68 Subkey Key::subkey(unsigned int index) const
   69 {
   70     return Subkey(key, index);
   71 }
   72 
   73 unsigned int Key::numUserIDs() const
   74 {
   75     if (!key) {
   76         return 0;
   77     }
   78     unsigned int count = 0;
   79     for (gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next) {
   80         ++count;
   81     }
   82     return count;
   83 }
   84 
   85 unsigned int Key::numSubkeys() const
   86 {
   87     if (!key) {
   88         return 0;
   89     }
   90     unsigned int count = 0;
   91     for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
   92         ++count;
   93     }
   94     return count;
   95 }
   96 
   97 std::vector<UserID> Key::userIDs() const
   98 {
   99     if (!key) {
  100         return std::vector<UserID>();
  101     }
  102 
  103     std::vector<UserID> v;
  104     v.reserve(numUserIDs());
  105     for (gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next) {
  106         v.push_back(UserID(key, uid));
  107     }
  108     return v;
  109 }
  110 
  111 std::vector<Subkey> Key::subkeys() const
  112 {
  113     if (!key) {
  114         return std::vector<Subkey>();
  115     }
  116 
  117     std::vector<Subkey> v;
  118     v.reserve(numSubkeys());
  119     for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
  120         v.push_back(Subkey(key, subkey));
  121     }
  122     return v;
  123 }
  124 
  125 Key::OwnerTrust Key::ownerTrust() const
  126 {
  127     if (!key) {
  128         return Unknown;
  129     }
  130     switch (key->owner_trust) {
  131     default:
  132     case GPGME_VALIDITY_UNKNOWN:   return Unknown;
  133     case GPGME_VALIDITY_UNDEFINED: return Undefined;
  134     case GPGME_VALIDITY_NEVER:     return Never;
  135     case GPGME_VALIDITY_MARGINAL:  return Marginal;
  136     case GPGME_VALIDITY_FULL:     return Full;
  137     case GPGME_VALIDITY_ULTIMATE: return Ultimate;
  138     }
  139 }
  140 char Key::ownerTrustAsString() const
  141 {
  142     if (!key) {
  143         return '?';
  144     }
  145     switch (key->owner_trust) {
  146     default:
  147     case GPGME_VALIDITY_UNKNOWN:   return '?';
  148     case GPGME_VALIDITY_UNDEFINED: return 'q';
  149     case GPGME_VALIDITY_NEVER:     return 'n';
  150     case GPGME_VALIDITY_MARGINAL:  return 'm';
  151     case GPGME_VALIDITY_FULL:     return 'f';
  152     case GPGME_VALIDITY_ULTIMATE: return 'u';
  153     }
  154 }
  155 
  156 Protocol Key::protocol() const
  157 {
  158     if (!key) {
  159         return UnknownProtocol;
  160     }
  161     switch (key->protocol) {
  162     case GPGME_PROTOCOL_CMS:     return CMS;
  163     case GPGME_PROTOCOL_OpenPGP: return OpenPGP;
  164     default:                     return UnknownProtocol;
  165     }
  166 }
  167 
  168 const char *Key::protocolAsString() const
  169 {
  170     return key ? gpgme_get_protocol_name(key->protocol) : nullptr ;
  171 }
  172 
  173 bool Key::isRevoked() const
  174 {
  175     return key && key->revoked;
  176 }
  177 
  178 bool Key::isExpired() const
  179 {
  180     return key && key->expired;
  181 }
  182 
  183 bool Key::isDisabled() const
  184 {
  185     return key && key->disabled;
  186 }
  187 
  188 bool Key::isInvalid() const
  189 {
  190     return key && key->invalid;
  191 }
  192 
  193 bool Key::hasSecret() const
  194 {
  195     return key && key->secret;
  196 }
  197 
  198 bool Key::isRoot() const
  199 {
  200     return key && key->subkeys && key->subkeys->fpr && key->chain_id &&
  201            strcasecmp(key->subkeys->fpr, key->chain_id) == 0;
  202 }
  203 
  204 bool Key::canEncrypt() const
  205 {
  206     return key && key->can_encrypt;
  207 }
  208 
  209 bool Key::canSign() const
  210 {
  211 #ifndef GPGME_CAN_SIGN_ON_SECRET_OPENPGP_KEYLISTING_NOT_BROKEN
  212     if (key && key->protocol == GPGME_PROTOCOL_OpenPGP) {
  213         return true;
  214     }
  215 #endif
  216     return canReallySign();
  217 }
  218 
  219 bool Key::canReallySign() const
  220 {
  221     return key && key->can_sign;
  222 }
  223 
  224 bool Key::canCertify() const
  225 {
  226     return key && key->can_certify;
  227 }
  228 
  229 bool Key::canAuthenticate() const
  230 {
  231     return key && key->can_authenticate;
  232 }
  233 
  234 bool Key::isQualified() const
  235 {
  236     return key && key->is_qualified;
  237 }
  238 
  239 bool Key::isDeVs() const
  240 {
  241     if (!key) {
  242         return false;
  243     }
  244     if (!key->subkeys || !key->subkeys->is_de_vs) {
  245         return false;
  246     }
  247     for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
  248         if (!subkey->is_de_vs) {
  249             return false;
  250         }
  251     }
  252     return true;
  253 }
  254 
  255 const char *Key::issuerSerial() const
  256 {
  257     return key ? key->issuer_serial : nullptr ;
  258 }
  259 const char *Key::issuerName() const
  260 {
  261     return key ? key->issuer_name : nullptr ;
  262 }
  263 const char *Key::chainID() const
  264 {
  265     return key ? key->chain_id : nullptr ;
  266 }
  267 
  268 const char *Key::keyID() const
  269 {
  270     return key && key->subkeys ? key->subkeys->keyid : nullptr ;
  271 }
  272 
  273 const char *Key::shortKeyID() const
  274 {
  275     if (!key || !key->subkeys || !key->subkeys->keyid) {
  276         return nullptr;
  277     }
  278     const int len = strlen(key->subkeys->keyid);
  279     if (len > 8) {
  280         return key->subkeys->keyid + len - 8; // return the last 8 bytes (in hex notation)
  281     } else {
  282         return key->subkeys->keyid;
  283     }
  284 }
  285 
  286 const char *Key::primaryFingerprint() const
  287 {
  288     if (!key) {
  289         return nullptr;
  290     }
  291     if (key->fpr) {
  292         /* Return what gpgme thinks is the primary fingerprint */
  293         return key->fpr;
  294     }
  295     if (key->subkeys) {
  296         /* Return the first subkeys fingerprint */
  297         return key->subkeys->fpr;
  298     }
  299     return nullptr;
  300 }
  301 
  302 unsigned int Key::keyListMode() const
  303 {
  304     return key ? convert_from_gpgme_keylist_mode_t(key->keylist_mode) : 0;
  305 }
  306 
  307 const Key &Key::mergeWith(const Key &other)
  308 {
  309     // ### incomplete. Just merges has* and can*, nothing else atm
  310     // ### detach also missing
  311 
  312     if (!this->primaryFingerprint() ||
  313             !other.primaryFingerprint() ||
  314             strcasecmp(this->primaryFingerprint(), other.primaryFingerprint()) != 0) {
  315         return *this; // only merge the Key object which describe the same key
  316     }
  317 
  318     const gpgme_key_t me = impl();
  319     const gpgme_key_t him = other.impl();
  320 
  321     if (!me || !him) {
  322         return *this;
  323     }
  324 
  325     me->revoked          |= him->revoked;
  326     me->expired          |= him->expired;
  327     me->disabled         |= him->disabled;
  328     me->invalid          |= him->invalid;
  329     me->can_encrypt      |= him->can_encrypt;
  330     me->can_sign         |= him->can_sign;
  331     me->can_certify      |= him->can_certify;
  332     me->secret           |= him->secret;
  333     me->can_authenticate |= him->can_authenticate;
  334     me->is_qualified     |= him->is_qualified;
  335     me->keylist_mode     |= him->keylist_mode;
  336 
  337     // make sure the gpgme_sub_key_t::is_cardkey flag isn't lost:
  338     for (gpgme_sub_key_t mysk = me->subkeys ; mysk ; mysk = mysk->next) {
  339         for (gpgme_sub_key_t hissk = him->subkeys ; hissk ; hissk = hissk->next) {
  340             if (strcmp(mysk->fpr, hissk->fpr) == 0) {
  341                 mysk->is_cardkey |= hissk->is_cardkey;
  342                 mysk->secret |= hissk->secret;
  343                 if (hissk->keygrip && !mysk->keygrip) {
  344                     mysk->keygrip = strdup(hissk->keygrip);
  345                 }
  346                 break;
  347             }
  348         }
  349     }
  350 
  351     return *this;
  352 }
  353 
  354 void Key::update()
  355 {
  356     if (isNull() || !primaryFingerprint()) {
  357         return;
  358     }
  359     auto ctx = Context::createForProtocol(protocol());
  360     if (!ctx) {
  361         return;
  362     }
  363     ctx->setKeyListMode(KeyListMode::Local |
  364                         KeyListMode::Signatures |
  365                         KeyListMode::SignatureNotations |
  366                         KeyListMode::Validate |
  367                         KeyListMode::WithTofu |
  368                         KeyListMode::WithKeygrip |
  369                         KeyListMode::WithSecret);
  370     Error err;
  371     Key newKey;
  372     if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.1.0") {
  373         newKey = ctx->key(primaryFingerprint(), err, true);
  374         // Not secret so we get the information from the pubring.
  375         if (newKey.isNull()) {
  376             newKey = ctx->key(primaryFingerprint(), err, false);
  377         }
  378     } else {
  379         newKey = ctx->key(primaryFingerprint(), err, false);
  380     }
  381     delete ctx;
  382     if (err) {
  383         return;
  384     }
  385     swap(newKey);
  386 }
  387 
  388 // static
  389 Key Key::locate(const char *mbox)
  390 {
  391     if (!mbox) {
  392         return Key();
  393     }
  394 
  395     auto ctx = Context::createForProtocol(OpenPGP);
  396     if (!ctx) {
  397         return Key();
  398     }
  399 
  400     ctx->setKeyListMode (Extern | Local);
  401 
  402     Error e = ctx->startKeyListing (mbox);
  403     auto ret = ctx->nextKey (e);
  404     delete ctx;
  405 
  406     return ret;
  407 }
  408 
  409 //
  410 //
  411 // class Subkey
  412 //
  413 //
  414 
  415 static gpgme_sub_key_t find_subkey(const shared_gpgme_key_t &key, unsigned int idx)
  416 {
  417     if (key) {
  418         for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next, --idx) {
  419             if (idx == 0) {
  420                 return s;
  421             }
  422         }
  423     }
  424     return nullptr;
  425 }
  426 
  427 static gpgme_sub_key_t verify_subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey)
  428 {
  429     if (key) {
  430         for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next) {
  431             if (s == subkey) {
  432                 return subkey;
  433             }
  434         }
  435     }
  436     return nullptr;
  437 }
  438 
  439 Subkey::Subkey() : key(), subkey(nullptr) {}
  440 
  441 Subkey::Subkey(const shared_gpgme_key_t &k, unsigned int idx)
  442     : key(k), subkey(find_subkey(k, idx))
  443 {
  444 
  445 }
  446 
  447 Subkey::Subkey(const shared_gpgme_key_t &k, gpgme_sub_key_t sk)
  448     : key(k), subkey(verify_subkey(k, sk))
  449 {
  450 
  451 }
  452 
  453 Key Subkey::parent() const
  454 {
  455     return Key(key);
  456 }
  457 
  458 const char *Subkey::keyID() const
  459 {
  460     return subkey ? subkey->keyid : nullptr ;
  461 }
  462 
  463 const char *Subkey::fingerprint() const
  464 {
  465     return subkey ? subkey->fpr : nullptr ;
  466 }
  467 
  468 Subkey::PubkeyAlgo Subkey::publicKeyAlgorithm() const
  469 {
  470     return subkey ? static_cast<PubkeyAlgo>(subkey->pubkey_algo) : AlgoUnknown;
  471 }
  472 
  473 const char *Subkey::publicKeyAlgorithmAsString() const
  474 {
  475     return gpgme_pubkey_algo_name(subkey ? subkey->pubkey_algo : (gpgme_pubkey_algo_t)0);
  476 }
  477 
  478 /* static */
  479 const char *Subkey::publicKeyAlgorithmAsString(PubkeyAlgo algo)
  480 {
  481     if (algo == AlgoUnknown) {
  482         return NULL;
  483     }
  484     return gpgme_pubkey_algo_name(static_cast<gpgme_pubkey_algo_t>(algo));
  485 }
  486 
  487 std::string Subkey::algoName() const
  488 {
  489     char *gpgmeStr;
  490     if (subkey && (gpgmeStr = gpgme_pubkey_algo_string(subkey))) {
  491         std::string ret = std::string(gpgmeStr);
  492         gpgme_free(gpgmeStr);
  493         return ret;
  494     }
  495     return std::string();
  496 }
  497 
  498 bool Subkey::canEncrypt() const
  499 {
  500     return subkey && subkey->can_encrypt;
  501 }
  502 
  503 bool Subkey::canSign() const
  504 {
  505     return subkey && subkey->can_sign;
  506 }
  507 
  508 bool Subkey::canCertify() const
  509 {
  510     return subkey && subkey->can_certify;
  511 }
  512 
  513 bool Subkey::canAuthenticate() const
  514 {
  515     return subkey && subkey->can_authenticate;
  516 }
  517 
  518 bool Subkey::isQualified() const
  519 {
  520     return subkey && subkey->is_qualified;
  521 }
  522 
  523 bool Subkey::isDeVs() const
  524 {
  525     return subkey && subkey->is_de_vs;
  526 }
  527 
  528 bool Subkey::isCardKey() const
  529 {
  530     return subkey && subkey->is_cardkey;
  531 }
  532 
  533 const char *Subkey::cardSerialNumber() const
  534 {
  535     return subkey ? subkey->card_number : nullptr;
  536 }
  537 
  538 const char *Subkey::keyGrip() const
  539 {
  540     return subkey ? subkey->keygrip : nullptr;
  541 }
  542 
  543 bool Subkey::isSecret() const
  544 {
  545     return subkey && subkey->secret;
  546 }
  547 
  548 unsigned int Subkey::length() const
  549 {
  550     return subkey ? subkey->length : 0 ;
  551 }
  552 
  553 time_t Subkey::creationTime() const
  554 {
  555     return static_cast<time_t>(subkey ? subkey->timestamp : 0);
  556 }
  557 
  558 time_t Subkey::expirationTime() const
  559 {
  560     return static_cast<time_t>(subkey ? subkey->expires : 0);
  561 }
  562 
  563 bool Subkey::neverExpires() const
  564 {
  565     return expirationTime() == time_t(0);
  566 }
  567 
  568 bool Subkey::isRevoked() const
  569 {
  570     return subkey && subkey->revoked;
  571 }
  572 
  573 bool Subkey::isInvalid() const
  574 {
  575     return subkey && subkey->invalid;
  576 }
  577 
  578 bool Subkey::isExpired() const
  579 {
  580     return subkey && subkey->expired;
  581 }
  582 
  583 bool Subkey::isDisabled() const
  584 {
  585     return subkey && subkey->disabled;
  586 }
  587 
  588 //
  589 //
  590 // class UserID
  591 //
  592 //
  593 
  594 static gpgme_user_id_t find_uid(const shared_gpgme_key_t &key, unsigned int idx)
  595 {
  596     if (key) {
  597         for (gpgme_user_id_t u = key->uids ; u ; u = u->next, --idx) {
  598             if (idx == 0) {
  599                 return u;
  600             }
  601         }
  602     }
  603     return nullptr;
  604 }
  605 
  606 static gpgme_user_id_t verify_uid(const shared_gpgme_key_t &key, gpgme_user_id_t uid)
  607 {
  608     if (key) {
  609         for (gpgme_user_id_t u = key->uids ; u ; u = u->next) {
  610             if (u == uid) {
  611                 return uid;
  612             }
  613         }
  614     }
  615     return nullptr;
  616 }
  617 
  618 UserID::UserID() : key(), uid(nullptr) {}
  619 
  620 UserID::UserID(const shared_gpgme_key_t &k, gpgme_user_id_t u)
  621     : key(k), uid(verify_uid(k, u))
  622 {
  623 
  624 }
  625 
  626 UserID::UserID(const shared_gpgme_key_t &k, unsigned int idx)
  627     : key(k), uid(find_uid(k, idx))
  628 {
  629 
  630 }
  631 
  632 Key UserID::parent() const
  633 {
  634     return Key(key);
  635 }
  636 
  637 UserID::Signature UserID::signature(unsigned int index) const
  638 {
  639     return Signature(key, uid, index);
  640 }
  641 
  642 unsigned int UserID::numSignatures() const
  643 {
  644     if (!uid) {
  645         return 0;
  646     }
  647     unsigned int count = 0;
  648     for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) {
  649         ++count;
  650     }
  651     return count;
  652 }
  653 
  654 std::vector<UserID::Signature> UserID::signatures() const
  655 {
  656     if (!uid) {
  657         return std::vector<Signature>();
  658     }
  659 
  660     std::vector<Signature> v;
  661     v.reserve(numSignatures());
  662     for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) {
  663         v.push_back(Signature(key, uid, sig));
  664     }
  665     return v;
  666 }
  667 
  668 const char *UserID::id() const
  669 {
  670     return uid ? uid->uid : nullptr ;
  671 }
  672 
  673 const char *UserID::name() const
  674 {
  675     return uid ? uid->name : nullptr ;
  676 }
  677 
  678 const char *UserID::email() const
  679 {
  680     return uid ? uid->email : nullptr ;
  681 }
  682 
  683 const char *UserID::comment() const
  684 {
  685     return uid ? uid->comment : nullptr ;
  686 }
  687 
  688 const char *UserID::uidhash() const
  689 {
  690     return uid ? uid->uidhash : nullptr ;
  691 }
  692 
  693 UserID::Validity UserID::validity() const
  694 {
  695     if (!uid) {
  696         return Unknown;
  697     }
  698     switch (uid->validity) {
  699     default:
  700     case GPGME_VALIDITY_UNKNOWN:   return Unknown;
  701     case GPGME_VALIDITY_UNDEFINED: return Undefined;
  702     case GPGME_VALIDITY_NEVER:     return Never;
  703     case GPGME_VALIDITY_MARGINAL:  return Marginal;
  704     case GPGME_VALIDITY_FULL:      return Full;
  705     case GPGME_VALIDITY_ULTIMATE:  return Ultimate;
  706     }
  707 }
  708 
  709 char UserID::validityAsString() const
  710 {
  711     if (!uid) {
  712         return '?';
  713     }
  714     switch (uid->validity) {
  715     default:
  716     case GPGME_VALIDITY_UNKNOWN:   return '?';
  717     case GPGME_VALIDITY_UNDEFINED: return 'q';
  718     case GPGME_VALIDITY_NEVER:     return 'n';
  719     case GPGME_VALIDITY_MARGINAL:  return 'm';
  720     case GPGME_VALIDITY_FULL:      return 'f';
  721     case GPGME_VALIDITY_ULTIMATE:  return 'u';
  722     }
  723 }
  724 
  725 bool UserID::isRevoked() const
  726 {
  727     return uid && uid->revoked;
  728 }
  729 
  730 bool UserID::isInvalid() const
  731 {
  732     return uid && uid->invalid;
  733 }
  734 
  735 TofuInfo UserID::tofuInfo() const
  736 {
  737     if (!uid) {
  738         return TofuInfo();
  739     }
  740     return TofuInfo(uid->tofu);
  741 }
  742 
  743 static gpgme_key_sig_t find_last_valid_sig_for_keyid (gpgme_user_id_t uid,
  744                                                       const char *keyid)
  745 {
  746     if (!keyid) {
  747         return nullptr;
  748     }
  749     gpgme_key_sig_t ret = NULL;
  750     for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next) {
  751         if (s->keyid && !strcmp(keyid, s->keyid)) {
  752             if (!s->expired && !s->revoked && !s->invalid && !s->status) {
  753                 if (!ret) {
  754                     ret = s;
  755                 } else if (ret && ret->timestamp <= s->timestamp) {
  756                     /* Equals because when the timestamps are the same we prefer
  757                        the last in the list */
  758                     ret = s;
  759                 }
  760             }
  761         }
  762     }
  763     return ret;
  764 }
  765 
  766 const char *UserID::remark(const Key &remarker, Error &err) const
  767 {
  768     if (!uid || remarker.isNull()) {
  769         err = Error::fromCode(GPG_ERR_GENERAL);
  770         return nullptr;
  771     }
  772 
  773     if (key->protocol != GPGME_PROTOCOL_OpenPGP) {
  774         return nullptr;
  775     }
  776 
  777     if (!(key->keylist_mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS) ||
  778         !(key->keylist_mode & GPGME_KEYLIST_MODE_SIGS)) {
  779         err = Error::fromCode(GPG_ERR_NO_DATA);
  780         return nullptr;
  781     }
  782 
  783     gpgme_key_sig_t s = find_last_valid_sig_for_keyid(uid, remarker.keyID());
  784 
  785     if (!s) {
  786         return nullptr;
  787     }
  788 
  789     for (gpgme_sig_notation_t n = s->notations; n ; n = n->next) {
  790         if (n->name && !strcmp(n->name, "rem@gnupg.org")) {
  791             return n->value;
  792         }
  793     }
  794     return nullptr;
  795 }
  796 
  797 std::vector<std::string> UserID::remarks(std::vector<Key> keys, Error &err) const
  798 {
  799     std::vector<std::string> ret;
  800 
  801     for (const auto &key: keys) {
  802         const char *rem = remark(key, err);
  803         if (err) {
  804             return ret;
  805         }
  806         if (rem) {
  807             ret.push_back(rem);
  808         }
  809     }
  810     return ret;
  811 }
  812 
  813 //
  814 //
  815 // class Signature
  816 //
  817 //
  818 
  819 static gpgme_key_sig_t find_signature(gpgme_user_id_t uid, unsigned int idx)
  820 {
  821     if (uid) {
  822         for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next, --idx) {
  823             if (idx == 0) {
  824                 return s;
  825             }
  826         }
  827     }
  828     return nullptr;
  829 }
  830 
  831 static gpgme_key_sig_t verify_signature(gpgme_user_id_t uid, gpgme_key_sig_t sig)
  832 {
  833     if (uid) {
  834         for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next) {
  835             if (s == sig) {
  836                 return sig;
  837             }
  838         }
  839     }
  840     return nullptr;
  841 }
  842 
  843 static int signature_index(gpgme_user_id_t uid, gpgme_key_sig_t sig)
  844 {
  845     if (uid) {
  846         int i = 0;
  847         for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next, ++i) {
  848             if (s == sig) {
  849                 return i;
  850             }
  851         }
  852     }
  853     return -1;
  854 }
  855 
  856 UserID::Signature::Signature() : key(), uid(nullptr), sig(nullptr) {}
  857 
  858 UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, unsigned int idx)
  859     : key(k), uid(verify_uid(k, u)), sig(find_signature(uid, idx))
  860 {
  861 }
  862 
  863 UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, gpgme_key_sig_t s)
  864     : key(k), uid(verify_uid(k, u)), sig(verify_signature(uid, s))
  865 {
  866 }
  867 
  868 bool UserID::Signature::operator<(const Signature &other)
  869 {
  870     // kept for binary compatibility
  871     return static_cast<const UserID::Signature *>(this)->operator<(other);
  872 }
  873 
  874 bool UserID::Signature::operator<(const Signature &other) const
  875 {
  876     // based on cmp_signodes() in g10/keylist.c
  877 
  878     // both signatures must belong to the same user ID
  879     assert(uid == other.uid);
  880 
  881     // self-signatures are ordered first
  882     const char *primaryKeyId = parent().parent().keyID();
  883     const bool thisIsSelfSignature = strcmp(signerKeyID(), primaryKeyId) == 0;
  884     const bool otherIsSelfSignature = strcmp(other.signerKeyID(), primaryKeyId) == 0;
  885     if (thisIsSelfSignature && !otherIsSelfSignature) {
  886         return true;
  887     }
  888     if (otherIsSelfSignature && !thisIsSelfSignature) {
  889         return false;
  890     }
  891 
  892     // then sort by signer key ID (which are or course the same for self-sigs)
  893     const int keyIdComparison = strcmp(signerKeyID(), other.signerKeyID());
  894     if (keyIdComparison < 0) {
  895         return true;
  896     }
  897     if (keyIdComparison > 0) {
  898         return false;
  899     }
  900 
  901     // followed by creation time
  902     if (creationTime() < other.creationTime()) {
  903         return true;
  904     }
  905     if (creationTime() > other.creationTime()) {
  906         return false;
  907     }
  908 
  909     // followed by the class in a way that a rev comes first
  910     if (certClass() < other.certClass()) {
  911         return true;
  912     }
  913     if (certClass() > other.certClass()) {
  914         return false;
  915     }
  916 
  917     // to make the sort stable we compare the indexes of the signatures as last resort
  918     return signature_index(uid, sig) < signature_index(uid, other.sig);
  919 }
  920 
  921 UserID UserID::Signature::parent() const
  922 {
  923     return UserID(key, uid);
  924 }
  925 
  926 const char *UserID::Signature::signerKeyID() const
  927 {
  928     return sig ? sig->keyid : nullptr ;
  929 }
  930 
  931 const char *UserID::Signature::algorithmAsString() const
  932 {
  933     return gpgme_pubkey_algo_name(sig ? sig->pubkey_algo : (gpgme_pubkey_algo_t)0);
  934 }
  935 
  936 unsigned int UserID::Signature::algorithm() const
  937 {
  938     return sig ? sig->pubkey_algo : 0 ;
  939 }
  940 
  941 time_t UserID::Signature::creationTime() const
  942 {
  943     return static_cast<time_t>(sig ? sig->timestamp : 0);
  944 }
  945 
  946 time_t UserID::Signature::expirationTime() const
  947 {
  948     return static_cast<time_t>(sig ? sig->expires : 0);
  949 }
  950 
  951 bool UserID::Signature::neverExpires() const
  952 {
  953     return expirationTime() == time_t(0);
  954 }
  955 
  956 bool UserID::Signature::isRevokation() const
  957 {
  958     return sig && sig->revoked;
  959 }
  960 
  961 bool UserID::Signature::isInvalid() const
  962 {
  963     return sig && sig->invalid;
  964 }
  965 
  966 bool UserID::Signature::isExpired() const
  967 {
  968     return sig && sig->expired;
  969 }
  970 
  971 bool UserID::Signature::isExportable() const
  972 {
  973     return sig && sig->exportable;
  974 }
  975 
  976 const char *UserID::Signature::signerUserID() const
  977 {
  978     return sig ? sig->uid : nullptr ;
  979 }
  980 
  981 const char *UserID::Signature::signerName() const
  982 {
  983     return sig ? sig->name : nullptr ;
  984 }
  985 
  986 const char *UserID::Signature::signerEmail() const
  987 {
  988     return sig ? sig->email : nullptr ;
  989 }
  990 
  991 const char *UserID::Signature::signerComment() const
  992 {
  993     return sig ? sig->comment : nullptr ;
  994 }
  995 
  996 unsigned int UserID::Signature::certClass() const
  997 {
  998     return sig ? sig->sig_class : 0 ;
  999 }
 1000 
 1001 UserID::Signature::Status UserID::Signature::status() const
 1002 {
 1003     if (!sig) {
 1004         return GeneralError;
 1005     }
 1006 
 1007     switch (gpgme_err_code(sig->status)) {
 1008     case GPG_ERR_NO_ERROR:      return NoError;
 1009     case GPG_ERR_SIG_EXPIRED:   return SigExpired;
 1010     case GPG_ERR_KEY_EXPIRED:   return KeyExpired;
 1011     case GPG_ERR_BAD_SIGNATURE: return BadSignature;
 1012     case GPG_ERR_NO_PUBKEY:     return NoPublicKey;
 1013     default:
 1014     case GPG_ERR_GENERAL:       return GeneralError;
 1015     }
 1016 }
 1017 
 1018 std::string UserID::Signature::statusAsString() const
 1019 {
 1020     if (!sig) {
 1021         return std::string();
 1022     }
 1023     char buf[ 1024 ];
 1024     gpgme_strerror_r(sig->status, buf, sizeof buf);
 1025     buf[ sizeof buf - 1 ] = '\0';
 1026     return std::string(buf);
 1027 }
 1028 
 1029 GpgME::Notation UserID::Signature::notation(unsigned int idx) const
 1030 {
 1031     if (!sig) {
 1032         return GpgME::Notation();
 1033     }
 1034     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
 1035         if (nota->name) {
 1036             if (idx-- == 0) {
 1037                 return GpgME::Notation(nota);
 1038             }
 1039         }
 1040     }
 1041     return GpgME::Notation();
 1042 }
 1043 
 1044 unsigned int UserID::Signature::numNotations() const
 1045 {
 1046     if (!sig) {
 1047         return 0;
 1048     }
 1049     unsigned int count = 0;
 1050     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
 1051         if (nota->name) {
 1052             ++count; // others are policy URLs...
 1053         }
 1054     }
 1055     return count;
 1056 }
 1057 
 1058 std::vector<Notation> UserID::Signature::notations() const
 1059 {
 1060     if (!sig) {
 1061         return std::vector<GpgME::Notation>();
 1062     }
 1063     std::vector<GpgME::Notation> v;
 1064     v.reserve(numNotations());
 1065     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
 1066         if (nota->name) {
 1067             v.push_back(GpgME::Notation(nota));
 1068         }
 1069     }
 1070     return v;
 1071 }
 1072 
 1073 const char *UserID::Signature::policyURL() const
 1074 {
 1075     if (!sig) {
 1076         return nullptr;
 1077     }
 1078     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
 1079         if (!nota->name) {
 1080             return nota->value;
 1081         }
 1082     }
 1083     return nullptr;
 1084 }
 1085 
 1086 std::string UserID::addrSpecFromString(const char *userid)
 1087 {
 1088     if (!userid) {
 1089         return std::string();
 1090     }
 1091     char *normalized = gpgme_addrspec_from_uid (userid);
 1092     if (normalized) {
 1093         std::string ret(normalized);
 1094         gpgme_free(normalized);
 1095         return ret;
 1096     }
 1097     return std::string();
 1098 }
 1099 
 1100 std::string UserID::addrSpec() const
 1101 {
 1102     if (!uid || !uid->address) {
 1103         return std::string();
 1104     }
 1105 
 1106     return uid->address;
 1107 }
 1108 
 1109 Error UserID::revoke()
 1110 {
 1111     if (isNull()) {
 1112         return Error::fromCode(GPG_ERR_GENERAL);
 1113     }
 1114     auto ctx = Context::createForProtocol(parent().protocol());
 1115     if (!ctx) {
 1116         return Error::fromCode(GPG_ERR_INV_ENGINE);
 1117     }
 1118     Error ret = ctx->revUid(key, id());
 1119     delete ctx;
 1120     return ret;
 1121 }
 1122 
 1123 static Key::Origin gpgme_origin_to_pp_origin (const unsigned int origin)
 1124 {
 1125     switch (origin) {
 1126         case GPGME_KEYORG_KS:
 1127             return Key::OriginKS;
 1128         case GPGME_KEYORG_DANE:
 1129             return Key::OriginDane;
 1130         case GPGME_KEYORG_WKD:
 1131             return Key::OriginWKD;
 1132         case GPGME_KEYORG_URL:
 1133             return Key::OriginURL;
 1134         case GPGME_KEYORG_FILE:
 1135             return Key::OriginFile;
 1136         case GPGME_KEYORG_SELF:
 1137             return Key::OriginSelf;
 1138         case GPGME_KEYORG_OTHER:
 1139             return Key::OriginOther;
 1140         case GPGME_KEYORG_UNKNOWN:
 1141         default:
 1142             return Key::OriginUnknown;
 1143     }
 1144 }
 1145 
 1146 Key::Origin UserID::origin() const
 1147 {
 1148     if (isNull()) {
 1149         return Key::OriginUnknown;
 1150     }
 1151     return gpgme_origin_to_pp_origin(uid->origin);
 1152 }
 1153 
 1154 time_t UserID::lastUpdate() const
 1155 {
 1156     return static_cast<time_t>(uid ? uid->last_update : 0);
 1157 }
 1158 
 1159 Error Key::addUid(const char *uid)
 1160 {
 1161     if (isNull()) {
 1162         return Error::fromCode(GPG_ERR_GENERAL);
 1163     }
 1164     auto ctx = Context::createForProtocol(protocol());
 1165     if (!ctx) {
 1166         return Error::fromCode(GPG_ERR_INV_ENGINE);
 1167     }
 1168     Error ret = ctx->addUid(key, uid);
 1169     delete ctx;
 1170     return ret;
 1171 }
 1172 
 1173 Key::Origin Key::origin() const
 1174 {
 1175     if (isNull()) {
 1176         return OriginUnknown;
 1177     }
 1178     return gpgme_origin_to_pp_origin(key->origin);
 1179 }
 1180 
 1181 time_t Key::lastUpdate() const
 1182 {
 1183     return static_cast<time_t>(key ? key->last_update : 0);
 1184 }
 1185 
 1186 bool Key::isBad() const
 1187 {
 1188     return isNull() || isRevoked() || isExpired() || isDisabled() || isInvalid();
 1189 }
 1190 
 1191 bool Subkey::isBad() const
 1192 {
 1193     return isNull() || isRevoked() || isExpired() || isDisabled() || isInvalid();
 1194 }
 1195 
 1196 bool UserID::isBad() const
 1197 {
 1198     return isNull() || isRevoked() || isInvalid();
 1199 }
 1200 
 1201 bool UserID::Signature::isBad() const
 1202 {
 1203     return isNull() || isExpired() || isInvalid();
 1204 }
 1205 
 1206 std::ostream &operator<<(std::ostream &os, const UserID &uid)
 1207 {
 1208     os << "GpgME::UserID(";
 1209     if (!uid.isNull()) {
 1210         os << "\n name:      " << protect(uid.name())
 1211            << "\n email:     " << protect(uid.email())
 1212            << "\n mbox:      " << uid.addrSpec()
 1213            << "\n comment:   " << protect(uid.comment())
 1214            << "\n validity:  " << uid.validityAsString()
 1215            << "\n revoked:   " << uid.isRevoked()
 1216            << "\n invalid:   " << uid.isInvalid()
 1217            << "\n numsigs:   " << uid.numSignatures()
 1218            << "\n origin:    " << uid.origin()
 1219            << "\n updated:   " << uid.lastUpdate()
 1220            << "\n tofuinfo:\n" << uid.tofuInfo();
 1221     }
 1222     return os << ')';
 1223 }
 1224 
 1225 std::ostream &operator<<(std::ostream &os, const Subkey &subkey)
 1226 {
 1227     os << "GpgME::Subkey(";
 1228     if (!subkey.isNull()) {
 1229         os << "\n fingerprint:   " << protect(subkey.fingerprint())
 1230            << "\n creationTime:  " << subkey.creationTime()
 1231            << "\n expirationTime:" << subkey.expirationTime()
 1232            << "\n isRevoked:     " << subkey.isRevoked()
 1233            << "\n isExpired:     " << subkey.isExpired()
 1234            << "\n isInvalid:     " << subkey.isRevoked()
 1235            << "\n isDisabled:    " << subkey.isInvalid()
 1236            << "\n canSign:       " << subkey.canSign()
 1237            << "\n canEncrypt:    " << subkey.canEncrypt()
 1238            << "\n canCertify:    " << subkey.canCertify()
 1239            << "\n canAuth:       " << subkey.canAuthenticate();
 1240     }
 1241     return os << ')';
 1242 }
 1243 
 1244 std::ostream &operator<<(std::ostream &os, const Key &key)
 1245 {
 1246     os << "GpgME::Key(";
 1247     if (!key.isNull()) {
 1248         os << "\n protocol:   " << protect(key.protocolAsString())
 1249            << "\n ownertrust: " << key.ownerTrustAsString()
 1250            << "\n issuer:     " << protect(key.issuerName())
 1251            << "\n fingerprint:" << protect(key.primaryFingerprint())
 1252            << "\n listmode:   " << key.keyListMode()
 1253            << "\n canSign:    " << key.canReallySign()
 1254            << "\n canEncrypt: " << key.canEncrypt()
 1255            << "\n canCertify: " << key.canCertify()
 1256            << "\n canAuth:    " << key.canAuthenticate()
 1257            << "\n origin:     " << key.origin()
 1258            << "\n updated:    " << key.lastUpdate()
 1259            << "\n uids:\n";
 1260         const std::vector<UserID> uids = key.userIDs();
 1261         std::copy(uids.begin(), uids.end(),
 1262                   std::ostream_iterator<UserID>(os, "\n"));
 1263         const std::vector<Subkey> subkeys = key.subkeys();
 1264         std::copy(subkeys.begin(), subkeys.end(),
 1265                   std::ostream_iterator<Subkey>(os, "\n"));
 1266     }
 1267     return os << ')';
 1268 }
 1269 
 1270 } // namespace GpgME