Revert "doc: Remove UI Server documentation"
[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         newKey = ctx->key(primaryFingerprint(), err, false);
367     }
368     delete ctx;
369     if (err) {
370         return;
371     }
372     swap(newKey);
373     return;
374 }
375
376 // static
377 Key Key::locate(const char *mbox)
378 {
379     if (!mbox) {
380         return Key();
381     }
382
383     auto ctx = Context::createForProtocol(OpenPGP);
384     if (!ctx) {
385         return Key();
386     }
387
388     ctx->setKeyListMode (Extern | Local);
389
390     Error e = ctx->startKeyListing (mbox);
391     auto ret = ctx->nextKey (e);
392     delete ctx;
393
394     return ret;
395 }
396
397 //
398 //
399 // class Subkey
400 //
401 //
402
403 gpgme_sub_key_t find_subkey(const shared_gpgme_key_t &key, unsigned int idx)
404 {
405     if (key) {
406         for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next, --idx) {
407             if (idx == 0) {
408                 return s;
409             }
410         }
411     }
412     return nullptr;
413 }
414
415 gpgme_sub_key_t verify_subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey)
416 {
417     if (key) {
418         for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next) {
419             if (s == subkey) {
420                 return subkey;
421             }
422         }
423     }
424     return nullptr;
425 }
426
427 Subkey::Subkey() : key(), subkey(nullptr) {}
428
429 Subkey::Subkey(const shared_gpgme_key_t &k, unsigned int idx)
430     : key(k), subkey(find_subkey(k, idx))
431 {
432
433 }
434
435 Subkey::Subkey(const shared_gpgme_key_t &k, gpgme_sub_key_t sk)
436     : key(k), subkey(verify_subkey(k, sk))
437 {
438
439 }
440
441 Key Subkey::parent() const
442 {
443     return Key(key);
444 }
445
446 const char *Subkey::keyID() const
447 {
448     return subkey ? subkey->keyid : nullptr ;
449 }
450
451 const char *Subkey::fingerprint() const
452 {
453     return subkey ? subkey->fpr : nullptr ;
454 }
455
456 Subkey::PubkeyAlgo Subkey::publicKeyAlgorithm() const
457 {
458     return subkey ? static_cast<PubkeyAlgo>(subkey->pubkey_algo) : AlgoUnknown;
459 }
460
461 const char *Subkey::publicKeyAlgorithmAsString() const
462 {
463     return gpgme_pubkey_algo_name(subkey ? subkey->pubkey_algo : (gpgme_pubkey_algo_t)0);
464 }
465
466 /* static */
467 const char *Subkey::publicKeyAlgorithmAsString(PubkeyAlgo algo)
468 {
469     if (algo == AlgoUnknown) {
470         return NULL;
471     }
472     return gpgme_pubkey_algo_name(static_cast<gpgme_pubkey_algo_t>(algo));
473 }
474
475 std::string Subkey::algoName() const
476 {
477     char *gpgmeStr;
478     if (subkey && (gpgmeStr = gpgme_pubkey_algo_string(subkey))) {
479         std::string ret = std::string(gpgmeStr);
480         gpgme_free(gpgmeStr);
481         return ret;
482     }
483     return std::string();
484 }
485
486 bool Subkey::canEncrypt() const
487 {
488     return subkey && subkey->can_encrypt;
489 }
490
491 bool Subkey::canSign() const
492 {
493     return subkey && subkey->can_sign;
494 }
495
496 bool Subkey::canCertify() const
497 {
498     return subkey && subkey->can_certify;
499 }
500
501 bool Subkey::canAuthenticate() const
502 {
503     return subkey && subkey->can_authenticate;
504 }
505
506 bool Subkey::isQualified() const
507 {
508     return subkey && subkey->is_qualified;
509 }
510
511 bool Subkey::isDeVs() const
512 {
513     return subkey && subkey->is_de_vs;
514 }
515
516 bool Subkey::isCardKey() const
517 {
518     return subkey && subkey->is_cardkey;
519 }
520
521 const char *Subkey::cardSerialNumber() const
522 {
523     return subkey ? subkey->card_number : nullptr;
524 }
525
526 const char *Subkey::keyGrip() const
527 {
528     return subkey ? subkey->keygrip : nullptr;
529 }
530
531 bool Subkey::isSecret() const
532 {
533     return subkey && subkey->secret;
534 }
535
536 unsigned int Subkey::length() const
537 {
538     return subkey ? subkey->length : 0 ;
539 }
540
541 time_t Subkey::creationTime() const
542 {
543     return static_cast<time_t>(subkey ? subkey->timestamp : 0);
544 }
545
546 time_t Subkey::expirationTime() const
547 {
548     return static_cast<time_t>(subkey ? subkey->expires : 0);
549 }
550
551 bool Subkey::neverExpires() const
552 {
553     return expirationTime() == time_t(0);
554 }
555
556 bool Subkey::isRevoked() const
557 {
558     return subkey && subkey->revoked;
559 }
560
561 bool Subkey::isInvalid() const
562 {
563     return subkey && subkey->invalid;
564 }
565
566 bool Subkey::isExpired() const
567 {
568     return subkey && subkey->expired;
569 }
570
571 bool Subkey::isDisabled() const
572 {
573     return subkey && subkey->disabled;
574 }
575
576 //
577 //
578 // class UserID
579 //
580 //
581
582 gpgme_user_id_t find_uid(const shared_gpgme_key_t &key, unsigned int idx)
583 {
584     if (key) {
585         for (gpgme_user_id_t u = key->uids ; u ; u = u->next, --idx) {
586             if (idx == 0) {
587                 return u;
588             }
589         }
590     }
591     return nullptr;
592 }
593
594 gpgme_user_id_t verify_uid(const shared_gpgme_key_t &key, gpgme_user_id_t uid)
595 {
596     if (key) {
597         for (gpgme_user_id_t u = key->uids ; u ; u = u->next) {
598             if (u == uid) {
599                 return uid;
600             }
601         }
602     }
603     return nullptr;
604 }
605
606 UserID::UserID() : key(), uid(nullptr) {}
607
608 UserID::UserID(const shared_gpgme_key_t &k, gpgme_user_id_t u)
609     : key(k), uid(verify_uid(k, u))
610 {
611
612 }
613
614 UserID::UserID(const shared_gpgme_key_t &k, unsigned int idx)
615     : key(k), uid(find_uid(k, idx))
616 {
617
618 }
619
620 Key UserID::parent() const
621 {
622     return Key(key);
623 }
624
625 UserID::Signature UserID::signature(unsigned int index) const
626 {
627     return Signature(key, uid, index);
628 }
629
630 unsigned int UserID::numSignatures() const
631 {
632     if (!uid) {
633         return 0;
634     }
635     unsigned int count = 0;
636     for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) {
637         ++count;
638     }
639     return count;
640 }
641
642 std::vector<UserID::Signature> UserID::signatures() const
643 {
644     if (!uid) {
645         return std::vector<Signature>();
646     }
647
648     std::vector<Signature> v;
649     v.reserve(numSignatures());
650     for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) {
651         v.push_back(Signature(key, uid, sig));
652     }
653     return v;
654 }
655
656 const char *UserID::id() const
657 {
658     return uid ? uid->uid : nullptr ;
659 }
660
661 const char *UserID::name() const
662 {
663     return uid ? uid->name : nullptr ;
664 }
665
666 const char *UserID::email() const
667 {
668     return uid ? uid->email : nullptr ;
669 }
670
671 const char *UserID::comment() const
672 {
673     return uid ? uid->comment : nullptr ;
674 }
675
676 UserID::Validity UserID::validity() const
677 {
678     if (!uid) {
679         return Unknown;
680     }
681     switch (uid->validity) {
682     default:
683     case GPGME_VALIDITY_UNKNOWN:   return Unknown;
684     case GPGME_VALIDITY_UNDEFINED: return Undefined;
685     case GPGME_VALIDITY_NEVER:     return Never;
686     case GPGME_VALIDITY_MARGINAL:  return Marginal;
687     case GPGME_VALIDITY_FULL:      return Full;
688     case GPGME_VALIDITY_ULTIMATE:  return Ultimate;
689     }
690 }
691
692 char UserID::validityAsString() const
693 {
694     if (!uid) {
695         return '?';
696     }
697     switch (uid->validity) {
698     default:
699     case GPGME_VALIDITY_UNKNOWN:   return '?';
700     case GPGME_VALIDITY_UNDEFINED: return 'q';
701     case GPGME_VALIDITY_NEVER:     return 'n';
702     case GPGME_VALIDITY_MARGINAL:  return 'm';
703     case GPGME_VALIDITY_FULL:      return 'f';
704     case GPGME_VALIDITY_ULTIMATE:  return 'u';
705     }
706 }
707
708 bool UserID::isRevoked() const
709 {
710     return uid && uid->revoked;
711 }
712
713 bool UserID::isInvalid() const
714 {
715     return uid && uid->invalid;
716 }
717
718 TofuInfo UserID::tofuInfo() const
719 {
720     if (!uid) {
721         return TofuInfo();
722     }
723     return TofuInfo(uid->tofu);
724 }
725
726 static gpgme_key_sig_t find_last_valid_sig_for_keyid (gpgme_user_id_t uid,
727                                                       const char *keyid)
728 {
729     if (!keyid) {
730         return nullptr;
731     }
732     gpgme_key_sig_t ret = NULL;
733     for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next) {
734         if (s->keyid && !strcmp(keyid, s->keyid)) {
735             if (!s->expired && !s->revoked && !s->invalid && !s->status) {
736                 if (!ret) {
737                     ret = s;
738                 } else if (ret && ret->timestamp <= s->timestamp) {
739                     /* Equals because when the timestamps are the same we prefer
740                        the last in the list */
741                     ret = s;
742                 }
743             }
744         }
745     }
746     return ret;
747 }
748
749 const char *UserID::remark(const Key &remarker, Error &err) const
750 {
751     if (!uid || remarker.isNull()) {
752         err = Error::fromCode(GPG_ERR_GENERAL);
753         return nullptr;
754     }
755
756     if (key->protocol != GPGME_PROTOCOL_OpenPGP) {
757         return nullptr;
758     }
759
760     if (!(key->keylist_mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS) ||
761         !(key->keylist_mode & GPGME_KEYLIST_MODE_SIGS)) {
762         err = Error::fromCode(GPG_ERR_NO_DATA);
763         return nullptr;
764     }
765
766     gpgme_key_sig_t s = find_last_valid_sig_for_keyid(uid, remarker.keyID());
767
768     if (!s) {
769         return nullptr;
770     }
771
772     for (gpgme_sig_notation_t n = s->notations; n ; n = n->next) {
773         if (n->name && !strcmp(n->name, "rem@gnupg.org")) {
774             return n->value;
775         }
776     }
777     return nullptr;
778 }
779
780 std::vector<std::string> UserID::remarks(std::vector<Key> keys, Error &err) const
781 {
782     std::vector<std::string> ret;
783
784     for (const auto &key: keys) {
785         const char *rem = remark(key, err);
786         if (err) {
787             return ret;
788         }
789         if (rem) {
790             ret.push_back(rem);
791         }
792     }
793     return ret;
794 }
795
796 //
797 //
798 // class Signature
799 //
800 //
801
802 gpgme_key_sig_t find_signature(gpgme_user_id_t uid, unsigned int idx)
803 {
804     if (uid) {
805         for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next, --idx) {
806             if (idx == 0) {
807                 return s;
808             }
809         }
810     }
811     return nullptr;
812 }
813
814 gpgme_key_sig_t verify_signature(gpgme_user_id_t uid, gpgme_key_sig_t sig)
815 {
816     if (uid) {
817         for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next) {
818             if (s == sig) {
819                 return sig;
820             }
821         }
822     }
823     return nullptr;
824 }
825
826 UserID::Signature::Signature() : key(), uid(nullptr), sig(nullptr) {}
827
828 UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, unsigned int idx)
829     : key(k), uid(verify_uid(k, u)), sig(find_signature(uid, idx))
830 {
831
832 }
833
834 UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, gpgme_key_sig_t s)
835     : key(k), uid(verify_uid(k, u)), sig(verify_signature(uid, s))
836 {
837
838 }
839
840 UserID UserID::Signature::parent() const
841 {
842     return UserID(key, uid);
843 }
844
845 const char *UserID::Signature::signerKeyID() const
846 {
847     return sig ? sig->keyid : nullptr ;
848 }
849
850 const char *UserID::Signature::algorithmAsString() const
851 {
852     return gpgme_pubkey_algo_name(sig ? sig->pubkey_algo : (gpgme_pubkey_algo_t)0);
853 }
854
855 unsigned int UserID::Signature::algorithm() const
856 {
857     return sig ? sig->pubkey_algo : 0 ;
858 }
859
860 time_t UserID::Signature::creationTime() const
861 {
862     return static_cast<time_t>(sig ? sig->timestamp : 0);
863 }
864
865 time_t UserID::Signature::expirationTime() const
866 {
867     return static_cast<time_t>(sig ? sig->expires : 0);
868 }
869
870 bool UserID::Signature::neverExpires() const
871 {
872     return expirationTime() == time_t(0);
873 }
874
875 bool UserID::Signature::isRevokation() const
876 {
877     return sig && sig->revoked;
878 }
879
880 bool UserID::Signature::isInvalid() const
881 {
882     return sig && sig->invalid;
883 }
884
885 bool UserID::Signature::isExpired() const
886 {
887     return sig && sig->expired;
888 }
889
890 bool UserID::Signature::isExportable() const
891 {
892     return sig && sig->exportable;
893 }
894
895 const char *UserID::Signature::signerUserID() const
896 {
897     return sig ? sig->uid : nullptr ;
898 }
899
900 const char *UserID::Signature::signerName() const
901 {
902     return sig ? sig->name : nullptr ;
903 }
904
905 const char *UserID::Signature::signerEmail() const
906 {
907     return sig ? sig->email : nullptr ;
908 }
909
910 const char *UserID::Signature::signerComment() const
911 {
912     return sig ? sig->comment : nullptr ;
913 }
914
915 unsigned int UserID::Signature::certClass() const
916 {
917     return sig ? sig->sig_class : 0 ;
918 }
919
920 UserID::Signature::Status UserID::Signature::status() const
921 {
922     if (!sig) {
923         return GeneralError;
924     }
925
926     switch (gpgme_err_code(sig->status)) {
927     case GPG_ERR_NO_ERROR:      return NoError;
928     case GPG_ERR_SIG_EXPIRED:   return SigExpired;
929     case GPG_ERR_KEY_EXPIRED:   return KeyExpired;
930     case GPG_ERR_BAD_SIGNATURE: return BadSignature;
931     case GPG_ERR_NO_PUBKEY:     return NoPublicKey;
932     default:
933     case GPG_ERR_GENERAL:       return GeneralError;
934     }
935 }
936
937 std::string UserID::Signature::statusAsString() const
938 {
939     if (!sig) {
940         return std::string();
941     }
942     char buf[ 1024 ];
943     gpgme_strerror_r(sig->status, buf, sizeof buf);
944     buf[ sizeof buf - 1 ] = '\0';
945     return std::string(buf);
946 }
947
948 GpgME::Notation UserID::Signature::notation(unsigned int idx) const
949 {
950     if (!sig) {
951         return GpgME::Notation();
952     }
953     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
954         if (nota->name) {
955             if (idx-- == 0) {
956                 return GpgME::Notation(nota);
957             }
958         }
959     }
960     return GpgME::Notation();
961 }
962
963 unsigned int UserID::Signature::numNotations() const
964 {
965     if (!sig) {
966         return 0;
967     }
968     unsigned int count = 0;
969     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
970         if (nota->name) {
971             ++count; // others are policy URLs...
972         }
973     }
974     return count;
975 }
976
977 std::vector<Notation> UserID::Signature::notations() const
978 {
979     if (!sig) {
980         return std::vector<GpgME::Notation>();
981     }
982     std::vector<GpgME::Notation> v;
983     v.reserve(numNotations());
984     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
985         if (nota->name) {
986             v.push_back(GpgME::Notation(nota));
987         }
988     }
989     return v;
990 }
991
992 const char *UserID::Signature::policyURL() const
993 {
994     if (!sig) {
995         return nullptr;
996     }
997     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
998         if (!nota->name) {
999             return nota->value;
1000         }
1001     }
1002     return nullptr;
1003 }
1004
1005 std::string UserID::addrSpecFromString(const char *userid)
1006 {
1007     if (!userid) {
1008         return std::string();
1009     }
1010     char *normalized = gpgme_addrspec_from_uid (userid);
1011     if (normalized) {
1012         std::string ret(normalized);
1013         gpgme_free(normalized);
1014         return ret;
1015     }
1016     return std::string();
1017 }
1018
1019 std::string UserID::addrSpec() const
1020 {
1021     if (!uid || !uid->address) {
1022         return std::string();
1023     }
1024
1025     return uid->address;
1026 }
1027
1028 Error UserID::revoke()
1029 {
1030     if (isNull()) {
1031         return Error::fromCode(GPG_ERR_GENERAL);
1032     }
1033     auto ctx = Context::createForProtocol(parent().protocol());
1034     if (!ctx) {
1035         return Error::fromCode(GPG_ERR_INV_ENGINE);
1036     }
1037     Error ret = ctx->revUid(key, id());
1038     delete ctx;
1039     return ret;
1040 }
1041
1042 static Key::Origin gpgme_origin_to_pp_origin (const unsigned int origin)
1043 {
1044     switch (origin) {
1045         case GPGME_KEYORG_KS:
1046             return Key::OriginKS;
1047         case GPGME_KEYORG_DANE:
1048             return Key::OriginDane;
1049         case GPGME_KEYORG_WKD:
1050             return Key::OriginWKD;
1051         case GPGME_KEYORG_URL:
1052             return Key::OriginURL;
1053         case GPGME_KEYORG_FILE:
1054             return Key::OriginFile;
1055         case GPGME_KEYORG_SELF:
1056             return Key::OriginSelf;
1057         case GPGME_KEYORG_OTHER:
1058             return Key::OriginOther;
1059         case GPGME_KEYORG_UNKNOWN:
1060         default:
1061             return Key::OriginUnknown;
1062     }
1063 }
1064
1065 Key::Origin UserID::origin() const
1066 {
1067     if (isNull()) {
1068         return Key::OriginUnknown;
1069     }
1070     return gpgme_origin_to_pp_origin(uid->origin);
1071 }
1072
1073 time_t UserID::lastUpdate() const
1074 {
1075     return static_cast<time_t>(uid ? uid->last_update : 0);
1076 }
1077
1078 Error Key::addUid(const char *uid)
1079 {
1080     if (isNull()) {
1081         return Error::fromCode(GPG_ERR_GENERAL);
1082     }
1083     auto ctx = Context::createForProtocol(protocol());
1084     if (!ctx) {
1085         return Error::fromCode(GPG_ERR_INV_ENGINE);
1086     }
1087     Error ret = ctx->addUid(key, uid);
1088     delete ctx;
1089     return ret;
1090 }
1091
1092 Key::Origin Key::origin() const
1093 {
1094     if (isNull()) {
1095         return OriginUnknown;
1096     }
1097     return gpgme_origin_to_pp_origin(key->origin);
1098 }
1099
1100 time_t Key::lastUpdate() const
1101 {
1102     return static_cast<time_t>(key ? key->last_update : 0);
1103 }
1104
1105 bool Key::isBad() const
1106 {
1107     return isNull() || isRevoked() || isExpired() || isDisabled() || isInvalid();
1108 }
1109
1110 bool Subkey::isBad() const
1111 {
1112     return isNull() || isRevoked() || isExpired() || isDisabled() || isInvalid();
1113 }
1114
1115 bool UserID::isBad() const
1116 {
1117     return isNull() || isRevoked() || isInvalid();
1118 }
1119
1120 bool UserID::Signature::isBad() const
1121 {
1122     return isNull() || isExpired() || isInvalid();
1123 }
1124
1125 std::ostream &operator<<(std::ostream &os, const UserID &uid)
1126 {
1127     os << "GpgME::UserID(";
1128     if (!uid.isNull()) {
1129         os << "\n name:      " << protect(uid.name())
1130            << "\n email:     " << protect(uid.email())
1131            << "\n mbox:      " << uid.addrSpec()
1132            << "\n comment:   " << protect(uid.comment())
1133            << "\n validity:  " << uid.validityAsString()
1134            << "\n revoked:   " << uid.isRevoked()
1135            << "\n invalid:   " << uid.isInvalid()
1136            << "\n numsigs:   " << uid.numSignatures()
1137            << "\n origin:    " << uid.origin()
1138            << "\n updated:   " << uid.lastUpdate()
1139            << "\n tofuinfo:\n" << uid.tofuInfo();
1140     }
1141     return os << ')';
1142 }
1143
1144 std::ostream &operator<<(std::ostream &os, const Key &key)
1145 {
1146     os << "GpgME::Key(";
1147     if (!key.isNull()) {
1148         os << "\n protocol:   " << protect(key.protocolAsString())
1149            << "\n ownertrust: " << key.ownerTrustAsString()
1150            << "\n issuer:     " << protect(key.issuerName())
1151            << "\n fingerprint:" << protect(key.primaryFingerprint())
1152            << "\n listmode:   " << key.keyListMode()
1153            << "\n canSign:    " << key.canReallySign()
1154            << "\n canEncrypt: " << key.canEncrypt()
1155            << "\n canCertify: " << key.canCertify()
1156            << "\n canAuth:    " << key.canAuthenticate()
1157            << "\n origin:     " << key.origin()
1158            << "\n updated:    " << key.lastUpdate()
1159            << "\n uids:\n";
1160         const std::vector<UserID> uids = key.userIDs();
1161         std::copy(uids.begin(), uids.end(),
1162                   std::ostream_iterator<UserID>(os, "\n"));
1163     }
1164     return os << ')';
1165 }
1166
1167 } // namespace GpgME