2 key.cpp - wraps a gpgme key
3 Copyright (C) 2003, 2005 Klarälvdalens Datakonsult AB
5 This file is part of GPGME++.
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.
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.
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.
40 const GpgME::Key::Null GpgME::Key::null;
47 Key::Key(const Null &) : key() {}
49 Key::Key(const shared_gpgme_key_t &k) : key(k) {}
51 Key::Key(gpgme_key_t k, bool ref)
53 ? shared_gpgme_key_t(k, &gpgme_key_unref)
54 : shared_gpgme_key_t())
57 gpgme_key_ref(impl());
61 UserID Key::userID(unsigned int index) const
63 return UserID(key, index);
66 Subkey Key::subkey(unsigned int index) const
68 return Subkey(key, index);
71 unsigned int Key::numUserIDs() const
76 unsigned int count = 0;
77 for (gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next) {
83 unsigned int Key::numSubkeys() const
88 unsigned int count = 0;
89 for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
95 std::vector<UserID> Key::userIDs() const
98 return std::vector<UserID>();
101 std::vector<UserID> v;
102 v.reserve(numUserIDs());
103 for (gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next) {
104 v.push_back(UserID(key, uid));
109 std::vector<Subkey> Key::subkeys() const
112 return std::vector<Subkey>();
115 std::vector<Subkey> v;
116 v.reserve(numSubkeys());
117 for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
118 v.push_back(Subkey(key, subkey));
123 Key::OwnerTrust Key::ownerTrust() const
128 switch (key->owner_trust) {
130 case GPGME_VALIDITY_UNKNOWN: return Unknown;
131 case GPGME_VALIDITY_UNDEFINED: return Undefined;
132 case GPGME_VALIDITY_NEVER: return Never;
133 case GPGME_VALIDITY_MARGINAL: return Marginal;
134 case GPGME_VALIDITY_FULL: return Full;
135 case GPGME_VALIDITY_ULTIMATE: return Ultimate;
138 char Key::ownerTrustAsString() const
143 switch (key->owner_trust) {
145 case GPGME_VALIDITY_UNKNOWN: return '?';
146 case GPGME_VALIDITY_UNDEFINED: return 'q';
147 case GPGME_VALIDITY_NEVER: return 'n';
148 case GPGME_VALIDITY_MARGINAL: return 'm';
149 case GPGME_VALIDITY_FULL: return 'f';
150 case GPGME_VALIDITY_ULTIMATE: return 'u';
154 Protocol Key::protocol() const
157 return UnknownProtocol;
159 switch (key->protocol) {
160 case GPGME_PROTOCOL_CMS: return CMS;
161 case GPGME_PROTOCOL_OpenPGP: return OpenPGP;
162 default: return UnknownProtocol;
166 const char *Key::protocolAsString() const
168 return key ? gpgme_get_protocol_name(key->protocol) : nullptr ;
171 bool Key::isRevoked() const
173 return key && key->revoked;
176 bool Key::isExpired() const
178 return key && key->expired;
181 bool Key::isDisabled() const
183 return key && key->disabled;
186 bool Key::isInvalid() const
188 return key && key->invalid;
191 bool Key::hasSecret() const
193 return key && key->secret;
196 bool Key::isRoot() const
198 return key && key->subkeys && key->subkeys->fpr && key->chain_id &&
199 strcasecmp(key->subkeys->fpr, key->chain_id) == 0;
202 bool Key::canEncrypt() const
204 return key && key->can_encrypt;
207 bool Key::canSign() const
209 #ifndef GPGME_CAN_SIGN_ON_SECRET_OPENPGP_KEYLISTING_NOT_BROKEN
210 if (key && key->protocol == GPGME_PROTOCOL_OpenPGP) {
214 return canReallySign();
217 bool Key::canReallySign() const
219 return key && key->can_sign;
222 bool Key::canCertify() const
224 return key && key->can_certify;
227 bool Key::canAuthenticate() const
229 return key && key->can_authenticate;
232 bool Key::isQualified() const
234 return key && key->is_qualified;
237 bool Key::isDeVs() const
242 if (!key->subkeys || !key->subkeys->is_de_vs) {
245 for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
246 if (!subkey->is_de_vs) {
253 const char *Key::issuerSerial() const
255 return key ? key->issuer_serial : nullptr ;
257 const char *Key::issuerName() const
259 return key ? key->issuer_name : nullptr ;
261 const char *Key::chainID() const
263 return key ? key->chain_id : nullptr ;
266 const char *Key::keyID() const
268 return key && key->subkeys ? key->subkeys->keyid : nullptr ;
271 const char *Key::shortKeyID() const
273 if (!key || !key->subkeys || !key->subkeys->keyid) {
276 const int len = strlen(key->subkeys->keyid);
278 return key->subkeys->keyid + len - 8; // return the last 8 bytes (in hex notation)
280 return key->subkeys->keyid;
284 const char *Key::primaryFingerprint() const
290 /* Return what gpgme thinks is the primary fingerprint */
294 /* Return the first subkeys fingerprint */
295 return key->subkeys->fpr;
300 unsigned int Key::keyListMode() const
302 return key ? convert_from_gpgme_keylist_mode_t(key->keylist_mode) : 0;
305 const Key &Key::mergeWith(const Key &other)
307 // ### incomplete. Just merges has* and can*, nothing else atm
308 // ### detach also missing
310 if (!this->primaryFingerprint() ||
311 !other.primaryFingerprint() ||
312 strcasecmp(this->primaryFingerprint(), other.primaryFingerprint()) != 0) {
313 return *this; // only merge the Key object which describe the same key
316 const gpgme_key_t me = impl();
317 const gpgme_key_t him = other.impl();
323 me->revoked |= him->revoked;
324 me->expired |= him->expired;
325 me->disabled |= him->disabled;
326 me->invalid |= him->invalid;
327 me->can_encrypt |= him->can_encrypt;
328 me->can_sign |= him->can_sign;
329 me->can_certify |= him->can_certify;
330 me->secret |= him->secret;
331 me->can_authenticate |= him->can_authenticate;
332 me->is_qualified |= him->is_qualified;
333 me->keylist_mode |= him->keylist_mode;
335 // make sure the gpgme_sub_key_t::is_cardkey flag isn't lost:
336 for (gpgme_sub_key_t mysk = me->subkeys ; mysk ; mysk = mysk->next) {
337 for (gpgme_sub_key_t hissk = him->subkeys ; hissk ; hissk = hissk->next) {
338 if (strcmp(mysk->fpr, hissk->fpr) == 0) {
339 mysk->is_cardkey |= hissk->is_cardkey;
350 if (isNull() || !primaryFingerprint()) {
353 auto ctx = Context::createForProtocol(protocol());
357 ctx->setKeyListMode(KeyListMode::Local |
358 KeyListMode::Signatures |
359 KeyListMode::SignatureNotations |
360 KeyListMode::Validate |
361 KeyListMode::WithTofu);
363 auto newKey = ctx->key(primaryFingerprint(), err, true);
364 // Not secret so we get the information from the pubring.
367 newKey = ctx->key(primaryFingerprint(), err, false);
378 Key Key::locate(const char *mbox)
384 auto ctx = Context::createForProtocol(OpenPGP);
389 ctx->setKeyListMode (Extern | Local);
391 Error e = ctx->startKeyListing (mbox);
392 auto ret = ctx->nextKey (e);
404 gpgme_sub_key_t find_subkey(const shared_gpgme_key_t &key, unsigned int idx)
407 for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next, --idx) {
416 gpgme_sub_key_t verify_subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey)
419 for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next) {
428 Subkey::Subkey() : key(), subkey(nullptr) {}
430 Subkey::Subkey(const shared_gpgme_key_t &k, unsigned int idx)
431 : key(k), subkey(find_subkey(k, idx))
436 Subkey::Subkey(const shared_gpgme_key_t &k, gpgme_sub_key_t sk)
437 : key(k), subkey(verify_subkey(k, sk))
442 Key Subkey::parent() const
447 const char *Subkey::keyID() const
449 return subkey ? subkey->keyid : nullptr ;
452 const char *Subkey::fingerprint() const
454 return subkey ? subkey->fpr : nullptr ;
457 Subkey::PubkeyAlgo Subkey::publicKeyAlgorithm() const
459 return subkey ? static_cast<PubkeyAlgo>(subkey->pubkey_algo) : AlgoUnknown;
462 const char *Subkey::publicKeyAlgorithmAsString() const
464 return gpgme_pubkey_algo_name(subkey ? subkey->pubkey_algo : (gpgme_pubkey_algo_t)0);
468 const char *Subkey::publicKeyAlgorithmAsString(PubkeyAlgo algo)
470 if (algo == AlgoUnknown) {
473 return gpgme_pubkey_algo_name(static_cast<gpgme_pubkey_algo_t>(algo));
476 std::string Subkey::algoName() const
479 if (subkey && (gpgmeStr = gpgme_pubkey_algo_string(subkey))) {
480 std::string ret = std::string(gpgmeStr);
481 gpgme_free(gpgmeStr);
484 return std::string();
487 bool Subkey::canEncrypt() const
489 return subkey && subkey->can_encrypt;
492 bool Subkey::canSign() const
494 return subkey && subkey->can_sign;
497 bool Subkey::canCertify() const
499 return subkey && subkey->can_certify;
502 bool Subkey::canAuthenticate() const
504 return subkey && subkey->can_authenticate;
507 bool Subkey::isQualified() const
509 return subkey && subkey->is_qualified;
512 bool Subkey::isDeVs() const
514 return subkey && subkey->is_de_vs;
517 bool Subkey::isCardKey() const
519 return subkey && subkey->is_cardkey;
522 const char *Subkey::cardSerialNumber() const
524 return subkey ? subkey->card_number : nullptr;
527 const char *Subkey::keyGrip() const
529 return subkey ? subkey->keygrip : nullptr;
532 bool Subkey::isSecret() const
534 return subkey && subkey->secret;
537 unsigned int Subkey::length() const
539 return subkey ? subkey->length : 0 ;
542 time_t Subkey::creationTime() const
544 return static_cast<time_t>(subkey ? subkey->timestamp : 0);
547 time_t Subkey::expirationTime() const
549 return static_cast<time_t>(subkey ? subkey->expires : 0);
552 bool Subkey::neverExpires() const
554 return expirationTime() == time_t(0);
557 bool Subkey::isRevoked() const
559 return subkey && subkey->revoked;
562 bool Subkey::isInvalid() const
564 return subkey && subkey->invalid;
567 bool Subkey::isExpired() const
569 return subkey && subkey->expired;
572 bool Subkey::isDisabled() const
574 return subkey && subkey->disabled;
583 gpgme_user_id_t find_uid(const shared_gpgme_key_t &key, unsigned int idx)
586 for (gpgme_user_id_t u = key->uids ; u ; u = u->next, --idx) {
595 gpgme_user_id_t verify_uid(const shared_gpgme_key_t &key, gpgme_user_id_t uid)
598 for (gpgme_user_id_t u = key->uids ; u ; u = u->next) {
607 UserID::UserID() : key(), uid(nullptr) {}
609 UserID::UserID(const shared_gpgme_key_t &k, gpgme_user_id_t u)
610 : key(k), uid(verify_uid(k, u))
615 UserID::UserID(const shared_gpgme_key_t &k, unsigned int idx)
616 : key(k), uid(find_uid(k, idx))
621 Key UserID::parent() const
626 UserID::Signature UserID::signature(unsigned int index) const
628 return Signature(key, uid, index);
631 unsigned int UserID::numSignatures() const
636 unsigned int count = 0;
637 for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) {
643 std::vector<UserID::Signature> UserID::signatures() const
646 return std::vector<Signature>();
649 std::vector<Signature> v;
650 v.reserve(numSignatures());
651 for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) {
652 v.push_back(Signature(key, uid, sig));
657 const char *UserID::id() const
659 return uid ? uid->uid : nullptr ;
662 const char *UserID::name() const
664 return uid ? uid->name : nullptr ;
667 const char *UserID::email() const
669 return uid ? uid->email : nullptr ;
672 const char *UserID::comment() const
674 return uid ? uid->comment : nullptr ;
677 UserID::Validity UserID::validity() const
682 switch (uid->validity) {
684 case GPGME_VALIDITY_UNKNOWN: return Unknown;
685 case GPGME_VALIDITY_UNDEFINED: return Undefined;
686 case GPGME_VALIDITY_NEVER: return Never;
687 case GPGME_VALIDITY_MARGINAL: return Marginal;
688 case GPGME_VALIDITY_FULL: return Full;
689 case GPGME_VALIDITY_ULTIMATE: return Ultimate;
693 char UserID::validityAsString() const
698 switch (uid->validity) {
700 case GPGME_VALIDITY_UNKNOWN: return '?';
701 case GPGME_VALIDITY_UNDEFINED: return 'q';
702 case GPGME_VALIDITY_NEVER: return 'n';
703 case GPGME_VALIDITY_MARGINAL: return 'm';
704 case GPGME_VALIDITY_FULL: return 'f';
705 case GPGME_VALIDITY_ULTIMATE: return 'u';
709 bool UserID::isRevoked() const
711 return uid && uid->revoked;
714 bool UserID::isInvalid() const
716 return uid && uid->invalid;
719 TofuInfo UserID::tofuInfo() const
724 return TofuInfo(uid->tofu);
733 gpgme_key_sig_t find_signature(gpgme_user_id_t uid, unsigned int idx)
736 for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next, --idx) {
745 gpgme_key_sig_t verify_signature(gpgme_user_id_t uid, gpgme_key_sig_t sig)
748 for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next) {
757 UserID::Signature::Signature() : key(), uid(nullptr), sig(nullptr) {}
759 UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, unsigned int idx)
760 : key(k), uid(verify_uid(k, u)), sig(find_signature(uid, idx))
765 UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, gpgme_key_sig_t s)
766 : key(k), uid(verify_uid(k, u)), sig(verify_signature(uid, s))
771 UserID UserID::Signature::parent() const
773 return UserID(key, uid);
776 const char *UserID::Signature::signerKeyID() const
778 return sig ? sig->keyid : nullptr ;
781 const char *UserID::Signature::algorithmAsString() const
783 return gpgme_pubkey_algo_name(sig ? sig->pubkey_algo : (gpgme_pubkey_algo_t)0);
786 unsigned int UserID::Signature::algorithm() const
788 return sig ? sig->pubkey_algo : 0 ;
791 time_t UserID::Signature::creationTime() const
793 return static_cast<time_t>(sig ? sig->timestamp : 0);
796 time_t UserID::Signature::expirationTime() const
798 return static_cast<time_t>(sig ? sig->expires : 0);
801 bool UserID::Signature::neverExpires() const
803 return expirationTime() == time_t(0);
806 bool UserID::Signature::isRevokation() const
808 return sig && sig->revoked;
811 bool UserID::Signature::isInvalid() const
813 return sig && sig->invalid;
816 bool UserID::Signature::isExpired() const
818 return sig && sig->expired;
821 bool UserID::Signature::isExportable() const
823 return sig && sig->exportable;
826 const char *UserID::Signature::signerUserID() const
828 return sig ? sig->uid : nullptr ;
831 const char *UserID::Signature::signerName() const
833 return sig ? sig->name : nullptr ;
836 const char *UserID::Signature::signerEmail() const
838 return sig ? sig->email : nullptr ;
841 const char *UserID::Signature::signerComment() const
843 return sig ? sig->comment : nullptr ;
846 unsigned int UserID::Signature::certClass() const
848 return sig ? sig->sig_class : 0 ;
851 UserID::Signature::Status UserID::Signature::status() const
857 switch (gpgme_err_code(sig->status)) {
858 case GPG_ERR_NO_ERROR: return NoError;
859 case GPG_ERR_SIG_EXPIRED: return SigExpired;
860 case GPG_ERR_KEY_EXPIRED: return KeyExpired;
861 case GPG_ERR_BAD_SIGNATURE: return BadSignature;
862 case GPG_ERR_NO_PUBKEY: return NoPublicKey;
864 case GPG_ERR_GENERAL: return GeneralError;
868 std::string UserID::Signature::statusAsString() const
871 return std::string();
874 gpgme_strerror_r(sig->status, buf, sizeof buf);
875 buf[ sizeof buf - 1 ] = '\0';
876 return std::string(buf);
879 GpgME::Notation UserID::Signature::notation(unsigned int idx) const
882 return GpgME::Notation();
884 for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
887 return GpgME::Notation(nota);
891 return GpgME::Notation();
894 unsigned int UserID::Signature::numNotations() const
899 unsigned int count = 0;
900 for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
902 ++count; // others are policy URLs...
908 std::vector<Notation> UserID::Signature::notations() const
911 return std::vector<GpgME::Notation>();
913 std::vector<GpgME::Notation> v;
914 v.reserve(numNotations());
915 for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
917 v.push_back(GpgME::Notation(nota));
923 const char *UserID::Signature::policyURL() const
928 for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
936 std::string UserID::addrSpecFromString(const char *userid)
939 return std::string();
941 char *normalized = gpgme_addrspec_from_uid (userid);
943 std::string ret(normalized);
944 gpgme_free(normalized);
947 return std::string();
950 std::string UserID::addrSpec() const
952 if (!uid || !uid->address) {
953 return std::string();
959 Error UserID::revoke()
962 return Error::fromCode(GPG_ERR_GENERAL);
964 auto ctx = Context::createForProtocol(parent().protocol());
966 return Error::fromCode(GPG_ERR_INV_ENGINE);
968 Error ret = ctx->revUid(key, id());
973 static Key::Origin gpgme_origin_to_pp_origin (const unsigned int origin)
976 case GPGME_KEYORG_KS:
977 return Key::OriginKS;
978 case GPGME_KEYORG_DANE:
979 return Key::OriginDane;
980 case GPGME_KEYORG_WKD:
981 return Key::OriginWKD;
982 case GPGME_KEYORG_URL:
983 return Key::OriginURL;
984 case GPGME_KEYORG_FILE:
985 return Key::OriginFile;
986 case GPGME_KEYORG_SELF:
987 return Key::OriginSelf;
988 case GPGME_KEYORG_OTHER:
989 return Key::OriginOther;
990 case GPGME_KEYORG_UNKNOWN:
992 return Key::OriginUnknown;
996 Key::Origin UserID::origin() const
999 return Key::OriginUnknown;
1001 return gpgme_origin_to_pp_origin(uid->origin);
1004 time_t UserID::lastUpdate() const
1006 return static_cast<time_t>(uid ? uid->last_update : 0);
1009 Error Key::addUid(const char *uid)
1012 return Error::fromCode(GPG_ERR_GENERAL);
1014 auto ctx = Context::createForProtocol(protocol());
1016 return Error::fromCode(GPG_ERR_INV_ENGINE);
1018 Error ret = ctx->addUid(key, uid);
1023 Key::Origin Key::origin() const
1026 return OriginUnknown;
1028 return gpgme_origin_to_pp_origin(key->origin);
1031 time_t Key::lastUpdate() const
1033 return static_cast<time_t>(key ? key->last_update : 0);
1036 bool Key::isBad() const
1038 return isNull() || isRevoked() || isExpired() || isDisabled() || isInvalid();
1041 bool Subkey::isBad() const
1043 return isNull() || isRevoked() || isExpired() || isDisabled() || isInvalid();
1046 bool UserID::isBad() const
1048 return isNull() || isRevoked() || isInvalid();
1051 bool UserID::Signature::isBad() const
1053 return isNull() || isExpired() || isInvalid();
1056 std::ostream &operator<<(std::ostream &os, const UserID &uid)
1058 os << "GpgME::UserID(";
1059 if (!uid.isNull()) {
1060 os << "\n name: " << protect(uid.name())
1061 << "\n email: " << protect(uid.email())
1062 << "\n mbox: " << uid.addrSpec()
1063 << "\n comment: " << protect(uid.comment())
1064 << "\n validity: " << uid.validityAsString()
1065 << "\n revoked: " << uid.isRevoked()
1066 << "\n invalid: " << uid.isInvalid()
1067 << "\n numsigs: " << uid.numSignatures()
1068 << "\n origin: " << uid.origin()
1069 << "\n updated: " << uid.lastUpdate()
1070 << "\n tofuinfo:\n" << uid.tofuInfo();
1075 std::ostream &operator<<(std::ostream &os, const Key &key)
1077 os << "GpgME::Key(";
1078 if (!key.isNull()) {
1079 os << "\n protocol: " << protect(key.protocolAsString())
1080 << "\n ownertrust: " << key.ownerTrustAsString()
1081 << "\n issuer: " << protect(key.issuerName())
1082 << "\n fingerprint:" << protect(key.primaryFingerprint())
1083 << "\n listmode: " << key.keyListMode()
1084 << "\n canSign: " << key.canReallySign()
1085 << "\n canEncrypt: " << key.canEncrypt()
1086 << "\n canCertify: " << key.canCertify()
1087 << "\n canAuth: " << key.canAuthenticate()
1088 << "\n origin: " << key.origin()
1089 << "\n updated: " << key.lastUpdate()
1091 const std::vector<UserID> uids = key.userIDs();
1092 std::copy(uids.begin(), uids.end(),
1093 std::ostream_iterator<UserID>(os, "\n"));
1098 } // namespace GpgME