4638fd8694be20e34fe124552e12973541891965
[platform/upstream/gpgme.git] / lang / cpp / src / key.cpp
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
33 #include <gpgme.h>
34
35 #include <string.h>
36 #include <strings.h>
37 #include <istream>
38 #include <iterator>
39
40 const GpgME::Key::Null GpgME::Key::null;
41
42 namespace GpgME
43 {
44
45 Key::Key() : key() {}
46
47 Key::Key(const Null &) : key() {}
48
49 Key::Key(const shared_gpgme_key_t &k) : key(k) {}
50
51 Key::Key(gpgme_key_t k, bool ref)
52     : key(k
53           ? shared_gpgme_key_t(k, &gpgme_key_unref)
54           : shared_gpgme_key_t())
55 {
56     if (ref && impl()) {
57         gpgme_key_ref(impl());
58     }
59 }
60
61 UserID Key::userID(unsigned int index) const
62 {
63     return UserID(key, index);
64 }
65
66 Subkey Key::subkey(unsigned int index) const
67 {
68     return Subkey(key, index);
69 }
70
71 unsigned int Key::numUserIDs() const
72 {
73     if (!key) {
74         return 0;
75     }
76     unsigned int count = 0;
77     for (gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next) {
78         ++count;
79     }
80     return count;
81 }
82
83 unsigned int Key::numSubkeys() const
84 {
85     if (!key) {
86         return 0;
87     }
88     unsigned int count = 0;
89     for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
90         ++count;
91     }
92     return count;
93 }
94
95 std::vector<UserID> Key::userIDs() const
96 {
97     if (!key) {
98         return std::vector<UserID>();
99     }
100
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));
105     }
106     return v;
107 }
108
109 std::vector<Subkey> Key::subkeys() const
110 {
111     if (!key) {
112         return std::vector<Subkey>();
113     }
114
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));
119     }
120     return v;
121 }
122
123 Key::OwnerTrust Key::ownerTrust() const
124 {
125     if (!key) {
126         return Unknown;
127     }
128     switch (key->owner_trust) {
129     default:
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;
136     }
137 }
138 char Key::ownerTrustAsString() const
139 {
140     if (!key) {
141         return '?';
142     }
143     switch (key->owner_trust) {
144     default:
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';
151     }
152 }
153
154 Protocol Key::protocol() const
155 {
156     if (!key) {
157         return UnknownProtocol;
158     }
159     switch (key->protocol) {
160     case GPGME_PROTOCOL_CMS:     return CMS;
161     case GPGME_PROTOCOL_OpenPGP: return OpenPGP;
162     default:                     return UnknownProtocol;
163     }
164 }
165
166 const char *Key::protocolAsString() const
167 {
168     return key ? gpgme_get_protocol_name(key->protocol) : nullptr ;
169 }
170
171 bool Key::isRevoked() const
172 {
173     return key && key->revoked;
174 }
175
176 bool Key::isExpired() const
177 {
178     return key && key->expired;
179 }
180
181 bool Key::isDisabled() const
182 {
183     return key && key->disabled;
184 }
185
186 bool Key::isInvalid() const
187 {
188     return key && key->invalid;
189 }
190
191 bool Key::hasSecret() const
192 {
193     return key && key->secret;
194 }
195
196 bool Key::isRoot() const
197 {
198     return key && key->subkeys && key->subkeys->fpr && key->chain_id &&
199            strcasecmp(key->subkeys->fpr, key->chain_id) == 0;
200 }
201
202 bool Key::canEncrypt() const
203 {
204     return key && key->can_encrypt;
205 }
206
207 bool Key::canSign() const
208 {
209 #ifndef GPGME_CAN_SIGN_ON_SECRET_OPENPGP_KEYLISTING_NOT_BROKEN
210     if (key && key->protocol == GPGME_PROTOCOL_OpenPGP) {
211         return true;
212     }
213 #endif
214     return canReallySign();
215 }
216
217 bool Key::canReallySign() const
218 {
219     return key && key->can_sign;
220 }
221
222 bool Key::canCertify() const
223 {
224     return key && key->can_certify;
225 }
226
227 bool Key::canAuthenticate() const
228 {
229     return key && key->can_authenticate;
230 }
231
232 bool Key::isQualified() const
233 {
234     return key && key->is_qualified;
235 }
236
237 bool Key::isDeVs() const
238 {
239     if (!key) {
240         return false;
241     }
242     if (!key->subkeys || !key->subkeys->is_de_vs) {
243         return false;
244     }
245     for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
246         if (!subkey->is_de_vs) {
247             return false;
248         }
249     }
250     return true;
251 }
252
253 const char *Key::issuerSerial() const
254 {
255     return key ? key->issuer_serial : nullptr ;
256 }
257 const char *Key::issuerName() const
258 {
259     return key ? key->issuer_name : nullptr ;
260 }
261 const char *Key::chainID() const
262 {
263     return key ? key->chain_id : nullptr ;
264 }
265
266 const char *Key::keyID() const
267 {
268     return key && key->subkeys ? key->subkeys->keyid : nullptr ;
269 }
270
271 const char *Key::shortKeyID() const
272 {
273     if (!key || !key->subkeys || !key->subkeys->keyid) {
274         return nullptr;
275     }
276     const int len = strlen(key->subkeys->keyid);
277     if (len > 8) {
278         return key->subkeys->keyid + len - 8; // return the last 8 bytes (in hex notation)
279     } else {
280         return key->subkeys->keyid;
281     }
282 }
283
284 const char *Key::primaryFingerprint() const
285 {
286     if (!key) {
287         return nullptr;
288     }
289     if (key->fpr) {
290         /* Return what gpgme thinks is the primary fingerprint */
291         return key->fpr;
292     }
293     if (key->subkeys) {
294         /* Return the first subkeys fingerprint */
295         return key->subkeys->fpr;
296     }
297     return nullptr;
298 }
299
300 unsigned int Key::keyListMode() const
301 {
302     return key ? convert_from_gpgme_keylist_mode_t(key->keylist_mode) : 0;
303 }
304
305 const Key &Key::mergeWith(const Key &other)
306 {
307     // ### incomplete. Just merges has* and can*, nothing else atm
308     // ### detach also missing
309
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
314     }
315
316     const gpgme_key_t me = impl();
317     const gpgme_key_t him = other.impl();
318
319     if (!me || !him) {
320         return *this;
321     }
322
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;
334
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;
340                 break;
341             }
342         }
343     }
344
345     return *this;
346 }
347
348 void Key::update()
349 {
350     if (isNull() || !primaryFingerprint()) {
351         return;
352     }
353     auto ctx = Context::createForProtocol(protocol());
354     if (!ctx) {
355         return;
356     }
357     ctx->setKeyListMode(KeyListMode::Local |
358                         KeyListMode::Signatures |
359                         KeyListMode::SignatureNotations |
360                         KeyListMode::Validate |
361                         KeyListMode::WithTofu);
362     Error err;
363     auto newKey = ctx->key(primaryFingerprint(), err, true);
364     // Not secret so we get the information from the pubring.
365     if (newKey.isNull())
366       {
367         newKey = ctx->key(primaryFingerprint(), err, false);
368       }
369     delete ctx;
370     if (err) {
371         return;
372     }
373     swap(newKey);
374     return;
375 }
376
377 // static
378 Key Key::locate(const char *mbox)
379 {
380     if (!mbox) {
381         return Key();
382     }
383
384     auto ctx = Context::createForProtocol(OpenPGP);
385     if (!ctx) {
386         return Key();
387     }
388
389     ctx->setKeyListMode (Extern | Local);
390
391     Error e = ctx->startKeyListing (mbox);
392     auto ret = ctx->nextKey (e);
393     delete ctx;
394
395     return ret;
396 }
397
398 //
399 //
400 // class Subkey
401 //
402 //
403
404 gpgme_sub_key_t find_subkey(const shared_gpgme_key_t &key, unsigned int idx)
405 {
406     if (key) {
407         for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next, --idx) {
408             if (idx == 0) {
409                 return s;
410             }
411         }
412     }
413     return nullptr;
414 }
415
416 gpgme_sub_key_t verify_subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey)
417 {
418     if (key) {
419         for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next) {
420             if (s == subkey) {
421                 return subkey;
422             }
423         }
424     }
425     return nullptr;
426 }
427
428 Subkey::Subkey() : key(), subkey(nullptr) {}
429
430 Subkey::Subkey(const shared_gpgme_key_t &k, unsigned int idx)
431     : key(k), subkey(find_subkey(k, idx))
432 {
433
434 }
435
436 Subkey::Subkey(const shared_gpgme_key_t &k, gpgme_sub_key_t sk)
437     : key(k), subkey(verify_subkey(k, sk))
438 {
439
440 }
441
442 Key Subkey::parent() const
443 {
444     return Key(key);
445 }
446
447 const char *Subkey::keyID() const
448 {
449     return subkey ? subkey->keyid : nullptr ;
450 }
451
452 const char *Subkey::fingerprint() const
453 {
454     return subkey ? subkey->fpr : nullptr ;
455 }
456
457 Subkey::PubkeyAlgo Subkey::publicKeyAlgorithm() const
458 {
459     return subkey ? static_cast<PubkeyAlgo>(subkey->pubkey_algo) : AlgoUnknown;
460 }
461
462 const char *Subkey::publicKeyAlgorithmAsString() const
463 {
464     return gpgme_pubkey_algo_name(subkey ? subkey->pubkey_algo : (gpgme_pubkey_algo_t)0);
465 }
466
467 /* static */
468 const char *Subkey::publicKeyAlgorithmAsString(PubkeyAlgo algo)
469 {
470     if (algo == AlgoUnknown) {
471         return NULL;
472     }
473     return gpgme_pubkey_algo_name(static_cast<gpgme_pubkey_algo_t>(algo));
474 }
475
476 std::string Subkey::algoName() const
477 {
478     char *gpgmeStr;
479     if (subkey && (gpgmeStr = gpgme_pubkey_algo_string(subkey))) {
480         std::string ret = std::string(gpgmeStr);
481         gpgme_free(gpgmeStr);
482         return ret;
483     }
484     return std::string();
485 }
486
487 bool Subkey::canEncrypt() const
488 {
489     return subkey && subkey->can_encrypt;
490 }
491
492 bool Subkey::canSign() const
493 {
494     return subkey && subkey->can_sign;
495 }
496
497 bool Subkey::canCertify() const
498 {
499     return subkey && subkey->can_certify;
500 }
501
502 bool Subkey::canAuthenticate() const
503 {
504     return subkey && subkey->can_authenticate;
505 }
506
507 bool Subkey::isQualified() const
508 {
509     return subkey && subkey->is_qualified;
510 }
511
512 bool Subkey::isDeVs() const
513 {
514     return subkey && subkey->is_de_vs;
515 }
516
517 bool Subkey::isCardKey() const
518 {
519     return subkey && subkey->is_cardkey;
520 }
521
522 const char *Subkey::cardSerialNumber() const
523 {
524     return subkey ? subkey->card_number : nullptr;
525 }
526
527 const char *Subkey::keyGrip() const
528 {
529     return subkey ? subkey->keygrip : nullptr;
530 }
531
532 bool Subkey::isSecret() const
533 {
534     return subkey && subkey->secret;
535 }
536
537 unsigned int Subkey::length() const
538 {
539     return subkey ? subkey->length : 0 ;
540 }
541
542 time_t Subkey::creationTime() const
543 {
544     return static_cast<time_t>(subkey ? subkey->timestamp : 0);
545 }
546
547 time_t Subkey::expirationTime() const
548 {
549     return static_cast<time_t>(subkey ? subkey->expires : 0);
550 }
551
552 bool Subkey::neverExpires() const
553 {
554     return expirationTime() == time_t(0);
555 }
556
557 bool Subkey::isRevoked() const
558 {
559     return subkey && subkey->revoked;
560 }
561
562 bool Subkey::isInvalid() const
563 {
564     return subkey && subkey->invalid;
565 }
566
567 bool Subkey::isExpired() const
568 {
569     return subkey && subkey->expired;
570 }
571
572 bool Subkey::isDisabled() const
573 {
574     return subkey && subkey->disabled;
575 }
576
577 //
578 //
579 // class UserID
580 //
581 //
582
583 gpgme_user_id_t find_uid(const shared_gpgme_key_t &key, unsigned int idx)
584 {
585     if (key) {
586         for (gpgme_user_id_t u = key->uids ; u ; u = u->next, --idx) {
587             if (idx == 0) {
588                 return u;
589             }
590         }
591     }
592     return nullptr;
593 }
594
595 gpgme_user_id_t verify_uid(const shared_gpgme_key_t &key, gpgme_user_id_t uid)
596 {
597     if (key) {
598         for (gpgme_user_id_t u = key->uids ; u ; u = u->next) {
599             if (u == uid) {
600                 return uid;
601             }
602         }
603     }
604     return nullptr;
605 }
606
607 UserID::UserID() : key(), uid(nullptr) {}
608
609 UserID::UserID(const shared_gpgme_key_t &k, gpgme_user_id_t u)
610     : key(k), uid(verify_uid(k, u))
611 {
612
613 }
614
615 UserID::UserID(const shared_gpgme_key_t &k, unsigned int idx)
616     : key(k), uid(find_uid(k, idx))
617 {
618
619 }
620
621 Key UserID::parent() const
622 {
623     return Key(key);
624 }
625
626 UserID::Signature UserID::signature(unsigned int index) const
627 {
628     return Signature(key, uid, index);
629 }
630
631 unsigned int UserID::numSignatures() const
632 {
633     if (!uid) {
634         return 0;
635     }
636     unsigned int count = 0;
637     for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) {
638         ++count;
639     }
640     return count;
641 }
642
643 std::vector<UserID::Signature> UserID::signatures() const
644 {
645     if (!uid) {
646         return std::vector<Signature>();
647     }
648
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));
653     }
654     return v;
655 }
656
657 const char *UserID::id() const
658 {
659     return uid ? uid->uid : nullptr ;
660 }
661
662 const char *UserID::name() const
663 {
664     return uid ? uid->name : nullptr ;
665 }
666
667 const char *UserID::email() const
668 {
669     return uid ? uid->email : nullptr ;
670 }
671
672 const char *UserID::comment() const
673 {
674     return uid ? uid->comment : nullptr ;
675 }
676
677 UserID::Validity UserID::validity() const
678 {
679     if (!uid) {
680         return Unknown;
681     }
682     switch (uid->validity) {
683     default:
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;
690     }
691 }
692
693 char UserID::validityAsString() const
694 {
695     if (!uid) {
696         return '?';
697     }
698     switch (uid->validity) {
699     default:
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';
706     }
707 }
708
709 bool UserID::isRevoked() const
710 {
711     return uid && uid->revoked;
712 }
713
714 bool UserID::isInvalid() const
715 {
716     return uid && uid->invalid;
717 }
718
719 TofuInfo UserID::tofuInfo() const
720 {
721     if (!uid) {
722         return TofuInfo();
723     }
724     return TofuInfo(uid->tofu);
725 }
726
727 //
728 //
729 // class Signature
730 //
731 //
732
733 gpgme_key_sig_t find_signature(gpgme_user_id_t uid, unsigned int idx)
734 {
735     if (uid) {
736         for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next, --idx) {
737             if (idx == 0) {
738                 return s;
739             }
740         }
741     }
742     return nullptr;
743 }
744
745 gpgme_key_sig_t verify_signature(gpgme_user_id_t uid, gpgme_key_sig_t sig)
746 {
747     if (uid) {
748         for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next) {
749             if (s == sig) {
750                 return sig;
751             }
752         }
753     }
754     return nullptr;
755 }
756
757 UserID::Signature::Signature() : key(), uid(nullptr), sig(nullptr) {}
758
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))
761 {
762
763 }
764
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))
767 {
768
769 }
770
771 UserID UserID::Signature::parent() const
772 {
773     return UserID(key, uid);
774 }
775
776 const char *UserID::Signature::signerKeyID() const
777 {
778     return sig ? sig->keyid : nullptr ;
779 }
780
781 const char *UserID::Signature::algorithmAsString() const
782 {
783     return gpgme_pubkey_algo_name(sig ? sig->pubkey_algo : (gpgme_pubkey_algo_t)0);
784 }
785
786 unsigned int UserID::Signature::algorithm() const
787 {
788     return sig ? sig->pubkey_algo : 0 ;
789 }
790
791 time_t UserID::Signature::creationTime() const
792 {
793     return static_cast<time_t>(sig ? sig->timestamp : 0);
794 }
795
796 time_t UserID::Signature::expirationTime() const
797 {
798     return static_cast<time_t>(sig ? sig->expires : 0);
799 }
800
801 bool UserID::Signature::neverExpires() const
802 {
803     return expirationTime() == time_t(0);
804 }
805
806 bool UserID::Signature::isRevokation() const
807 {
808     return sig && sig->revoked;
809 }
810
811 bool UserID::Signature::isInvalid() const
812 {
813     return sig && sig->invalid;
814 }
815
816 bool UserID::Signature::isExpired() const
817 {
818     return sig && sig->expired;
819 }
820
821 bool UserID::Signature::isExportable() const
822 {
823     return sig && sig->exportable;
824 }
825
826 const char *UserID::Signature::signerUserID() const
827 {
828     return sig ? sig->uid : nullptr ;
829 }
830
831 const char *UserID::Signature::signerName() const
832 {
833     return sig ? sig->name : nullptr ;
834 }
835
836 const char *UserID::Signature::signerEmail() const
837 {
838     return sig ? sig->email : nullptr ;
839 }
840
841 const char *UserID::Signature::signerComment() const
842 {
843     return sig ? sig->comment : nullptr ;
844 }
845
846 unsigned int UserID::Signature::certClass() const
847 {
848     return sig ? sig->sig_class : 0 ;
849 }
850
851 UserID::Signature::Status UserID::Signature::status() const
852 {
853     if (!sig) {
854         return GeneralError;
855     }
856
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;
863     default:
864     case GPG_ERR_GENERAL:       return GeneralError;
865     }
866 }
867
868 std::string UserID::Signature::statusAsString() const
869 {
870     if (!sig) {
871         return std::string();
872     }
873     char buf[ 1024 ];
874     gpgme_strerror_r(sig->status, buf, sizeof buf);
875     buf[ sizeof buf - 1 ] = '\0';
876     return std::string(buf);
877 }
878
879 GpgME::Notation UserID::Signature::notation(unsigned int idx) const
880 {
881     if (!sig) {
882         return GpgME::Notation();
883     }
884     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
885         if (nota->name) {
886             if (idx-- == 0) {
887                 return GpgME::Notation(nota);
888             }
889         }
890     }
891     return GpgME::Notation();
892 }
893
894 unsigned int UserID::Signature::numNotations() const
895 {
896     if (!sig) {
897         return 0;
898     }
899     unsigned int count = 0;
900     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
901         if (nota->name) {
902             ++count; // others are policy URLs...
903         }
904     }
905     return count;
906 }
907
908 std::vector<Notation> UserID::Signature::notations() const
909 {
910     if (!sig) {
911         return std::vector<GpgME::Notation>();
912     }
913     std::vector<GpgME::Notation> v;
914     v.reserve(numNotations());
915     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
916         if (nota->name) {
917             v.push_back(GpgME::Notation(nota));
918         }
919     }
920     return v;
921 }
922
923 const char *UserID::Signature::policyURL() const
924 {
925     if (!sig) {
926         return nullptr;
927     }
928     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
929         if (!nota->name) {
930             return nota->value;
931         }
932     }
933     return nullptr;
934 }
935
936 std::string UserID::addrSpecFromString(const char *userid)
937 {
938     if (!userid) {
939         return std::string();
940     }
941     char *normalized = gpgme_addrspec_from_uid (userid);
942     if (normalized) {
943         std::string ret(normalized);
944         gpgme_free(normalized);
945         return ret;
946     }
947     return std::string();
948 }
949
950 std::string UserID::addrSpec() const
951 {
952     if (!uid || !uid->address) {
953         return std::string();
954     }
955
956     return uid->address;
957 }
958
959 Error UserID::revoke()
960 {
961     if (isNull()) {
962         return Error::fromCode(GPG_ERR_GENERAL);
963     }
964     auto ctx = Context::createForProtocol(parent().protocol());
965     if (!ctx) {
966         return Error::fromCode(GPG_ERR_INV_ENGINE);
967     }
968     Error ret = ctx->revUid(key, id());
969     delete ctx;
970     return ret;
971 }
972
973 static Key::Origin gpgme_origin_to_pp_origin (const unsigned int origin)
974 {
975     switch (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:
991         default:
992             return Key::OriginUnknown;
993     }
994 }
995
996 Key::Origin UserID::origin() const
997 {
998     if (isNull()) {
999         return Key::OriginUnknown;
1000     }
1001     return gpgme_origin_to_pp_origin(uid->origin);
1002 }
1003
1004 time_t UserID::lastUpdate() const
1005 {
1006     return static_cast<time_t>(uid ? uid->last_update : 0);
1007 }
1008
1009 Error Key::addUid(const char *uid)
1010 {
1011     if (isNull()) {
1012         return Error::fromCode(GPG_ERR_GENERAL);
1013     }
1014     auto ctx = Context::createForProtocol(protocol());
1015     if (!ctx) {
1016         return Error::fromCode(GPG_ERR_INV_ENGINE);
1017     }
1018     Error ret = ctx->addUid(key, uid);
1019     delete ctx;
1020     return ret;
1021 }
1022
1023 Key::Origin Key::origin() const
1024 {
1025     if (isNull()) {
1026         return OriginUnknown;
1027     }
1028     return gpgme_origin_to_pp_origin(key->origin);
1029 }
1030
1031 time_t Key::lastUpdate() const
1032 {
1033     return static_cast<time_t>(key ? key->last_update : 0);
1034 }
1035
1036 bool Key::isBad() const
1037 {
1038     return isNull() || isRevoked() || isExpired() || isDisabled() || isInvalid();
1039 }
1040
1041 bool Subkey::isBad() const
1042 {
1043     return isNull() || isRevoked() || isExpired() || isDisabled() || isInvalid();
1044 }
1045
1046 bool UserID::isBad() const
1047 {
1048     return isNull() || isRevoked() || isInvalid();
1049 }
1050
1051 bool UserID::Signature::isBad() const
1052 {
1053     return isNull() || isExpired() || isInvalid();
1054 }
1055
1056 std::ostream &operator<<(std::ostream &os, const UserID &uid)
1057 {
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();
1071     }
1072     return os << ')';
1073 }
1074
1075 std::ostream &operator<<(std::ostream &os, const Key &key)
1076 {
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()
1090            << "\n uids:\n";
1091         const std::vector<UserID> uids = key.userIDs();
1092         std::copy(uids.begin(), uids.end(),
1093                   std::ostream_iterator<UserID>(os, "\n"));
1094     }
1095     return os << ')';
1096 }
1097
1098 } // namespace GpgME