6f40f66672fd29ed0f3a809c6b24444ef76238b0
[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 #include <key.h>
24
25 #include "util.h"
26 #include "tofuinfo.h"
27
28 #include <gpgme.h>
29
30 #include <string.h>
31
32 const GpgME::Key::Null GpgME::Key::null;
33
34 namespace GpgME
35 {
36
37 Key::Key() : key() {}
38
39 Key::Key(const Null &) : key() {}
40
41 Key::Key(const shared_gpgme_key_t &k) : key(k) {}
42
43 Key::Key(gpgme_key_t k, bool ref)
44     : key(k
45           ? shared_gpgme_key_t(k, &gpgme_key_unref)
46           : shared_gpgme_key_t())
47 {
48     if (ref && impl()) {
49         gpgme_key_ref(impl());
50     }
51 }
52
53 UserID Key::userID(unsigned int index) const
54 {
55     return UserID(key, index);
56 }
57
58 Subkey Key::subkey(unsigned int index) const
59 {
60     return Subkey(key, index);
61 }
62
63 unsigned int Key::numUserIDs() const
64 {
65     if (!key) {
66         return 0;
67     }
68     unsigned int count = 0;
69     for (gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next) {
70         ++count;
71     }
72     return count;
73 }
74
75 unsigned int Key::numSubkeys() const
76 {
77     if (!key) {
78         return 0;
79     }
80     unsigned int count = 0;
81     for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
82         ++count;
83     }
84     return count;
85 }
86
87 std::vector<UserID> Key::userIDs() const
88 {
89     if (!key) {
90         return std::vector<UserID>();
91     }
92
93     std::vector<UserID> v;
94     v.reserve(numUserIDs());
95     for (gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next) {
96         v.push_back(UserID(key, uid));
97     }
98     return v;
99 }
100
101 std::vector<Subkey> Key::subkeys() const
102 {
103     if (!key) {
104         return std::vector<Subkey>();
105     }
106
107     std::vector<Subkey> v;
108     v.reserve(numSubkeys());
109     for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
110         v.push_back(Subkey(key, subkey));
111     }
112     return v;
113 }
114
115 Key::OwnerTrust Key::ownerTrust() const
116 {
117     if (!key) {
118         return Unknown;
119     }
120     switch (key->owner_trust) {
121     default:
122     case GPGME_VALIDITY_UNKNOWN:   return Unknown;
123     case GPGME_VALIDITY_UNDEFINED: return Undefined;
124     case GPGME_VALIDITY_NEVER:     return Never;
125     case GPGME_VALIDITY_MARGINAL:  return Marginal;
126     case GPGME_VALIDITY_FULL:     return Full;
127     case GPGME_VALIDITY_ULTIMATE: return Ultimate;
128     }
129 }
130 char Key::ownerTrustAsString() const
131 {
132     if (!key) {
133         return '?';
134     }
135     switch (key->owner_trust) {
136     default:
137     case GPGME_VALIDITY_UNKNOWN:   return '?';
138     case GPGME_VALIDITY_UNDEFINED: return 'q';
139     case GPGME_VALIDITY_NEVER:     return 'n';
140     case GPGME_VALIDITY_MARGINAL:  return 'm';
141     case GPGME_VALIDITY_FULL:     return 'f';
142     case GPGME_VALIDITY_ULTIMATE: return 'u';
143     }
144 }
145
146 Protocol Key::protocol() const
147 {
148     if (!key) {
149         return UnknownProtocol;
150     }
151     switch (key->protocol) {
152     case GPGME_PROTOCOL_CMS:     return CMS;
153     case GPGME_PROTOCOL_OpenPGP: return OpenPGP;
154     default:                     return UnknownProtocol;
155     }
156 }
157
158 const char *Key::protocolAsString() const
159 {
160     return key ? gpgme_get_protocol_name(key->protocol) : 0 ;
161 }
162
163 bool Key::isRevoked() const
164 {
165     return key && key->revoked;
166 }
167
168 bool Key::isExpired() const
169 {
170     return key && key->expired;
171 }
172
173 bool Key::isDisabled() const
174 {
175     return key && key->disabled;
176 }
177
178 bool Key::isInvalid() const
179 {
180     return key && key->invalid;
181 }
182
183 bool Key::hasSecret() const
184 {
185     return key && key->secret;
186 }
187
188 bool Key::isRoot() const
189 {
190     return key && key->subkeys && key->subkeys->fpr && key->chain_id &&
191            strcasecmp(key->subkeys->fpr, key->chain_id) == 0;
192 }
193
194 bool Key::canEncrypt() const
195 {
196     return key && key->can_encrypt;
197 }
198
199 bool Key::canSign() const
200 {
201 #ifndef GPGME_CAN_SIGN_ON_SECRET_OPENPGP_KEYLISTING_NOT_BROKEN
202     if (key && key->protocol == GPGME_PROTOCOL_OpenPGP) {
203         return true;
204     }
205 #endif
206     return canReallySign();
207 }
208
209 bool Key::canReallySign() const
210 {
211     return key && key->can_sign;
212 }
213
214 bool Key::canCertify() const
215 {
216     return key && key->can_certify;
217 }
218
219 bool Key::canAuthenticate() const
220 {
221     return key && key->can_authenticate;
222 }
223
224 bool Key::isQualified() const
225 {
226     return key && key->is_qualified;
227 }
228
229 const char *Key::issuerSerial() const
230 {
231     return key ? key->issuer_serial : 0 ;
232 }
233 const char *Key::issuerName() const
234 {
235     return key ? key->issuer_name : 0 ;
236 }
237 const char *Key::chainID() const
238 {
239     return key ? key->chain_id : 0 ;
240 }
241
242 const char *Key::keyID() const
243 {
244     return key && key->subkeys ? key->subkeys->keyid : 0 ;
245 }
246
247 const char *Key::shortKeyID() const
248 {
249     if (!key || !key->subkeys || !key->subkeys->keyid) {
250         return 0;
251     }
252     const int len = strlen(key->subkeys->keyid);
253     if (len > 8) {
254         return key->subkeys->keyid + len - 8; // return the last 8 bytes (in hex notation)
255     } else {
256         return key->subkeys->keyid;
257     }
258 }
259
260 const char *Key::primaryFingerprint() const
261 {
262     if (!key) {
263         return nullptr;
264     }
265     if (key->fpr) {
266         /* Return what gpgme thinks is the primary fingerprint */
267         return key->fpr;
268     }
269     if (key->subkeys) {
270         /* Return the first subkeys fingerprint */
271         return key->subkeys->fpr;
272     }
273 }
274
275 unsigned int Key::keyListMode() const
276 {
277     return key ? convert_from_gpgme_keylist_mode_t(key->keylist_mode) : 0 ;
278 }
279
280 const Key &Key::mergeWith(const Key &other)
281 {
282     // ### incomplete. Just merges has* and can*, nothing else atm
283     // ### detach also missing
284
285     if (!this->primaryFingerprint() ||
286             !other.primaryFingerprint() ||
287             strcasecmp(this->primaryFingerprint(), other.primaryFingerprint()) != 0) {
288         return *this; // only merge the Key object which describe the same key
289     }
290
291     const gpgme_key_t me = impl();
292     const gpgme_key_t him = other.impl();
293
294     if (!me || !him) {
295         return *this;
296     }
297
298     me->revoked          |= him->revoked;
299     me->expired          |= him->expired;
300     me->disabled         |= him->disabled;
301     me->invalid          |= him->invalid;
302     me->can_encrypt      |= him->can_encrypt;
303     me->can_sign         |= him->can_sign;
304     me->can_certify      |= him->can_certify;
305     me->secret           |= him->secret;
306     me->can_authenticate |= him->can_authenticate;
307     me->is_qualified     |= him->is_qualified;
308     me->keylist_mode     |= him->keylist_mode;
309
310     // make sure the gpgme_sub_key_t::is_cardkey flag isn't lost:
311     for (gpgme_sub_key_t mysk = me->subkeys ; mysk ; mysk = mysk->next) {
312         for (gpgme_sub_key_t hissk = him->subkeys ; hissk ; hissk = hissk->next) {
313             if (strcmp(mysk->fpr, hissk->fpr) == 0) {
314                 mysk->is_cardkey |= hissk->is_cardkey;
315                 break;
316             }
317         }
318     }
319
320     return *this;
321 }
322
323 //
324 //
325 // class Subkey
326 //
327 //
328
329 gpgme_sub_key_t find_subkey(const shared_gpgme_key_t &key, unsigned int idx)
330 {
331     if (key) {
332         for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next, --idx) {
333             if (idx == 0) {
334                 return s;
335             }
336         }
337     }
338     return 0;
339 }
340
341 gpgme_sub_key_t verify_subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey)
342 {
343     if (key) {
344         for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next) {
345             if (s == subkey) {
346                 return subkey;
347             }
348         }
349     }
350     return 0;
351 }
352
353 Subkey::Subkey() : key(), subkey(0) {}
354
355 Subkey::Subkey(const shared_gpgme_key_t &k, unsigned int idx)
356     : key(k), subkey(find_subkey(k, idx))
357 {
358
359 }
360
361 Subkey::Subkey(const shared_gpgme_key_t &k, gpgme_sub_key_t sk)
362     : key(k), subkey(verify_subkey(k, sk))
363 {
364
365 }
366
367 Key Subkey::parent() const
368 {
369     return Key(key);
370 }
371
372 const char *Subkey::keyID() const
373 {
374     return subkey ? subkey->keyid : 0 ;
375 }
376
377 const char *Subkey::fingerprint() const
378 {
379     return subkey ? subkey->fpr : 0 ;
380 }
381
382 Subkey::PubkeyAlgo Subkey::publicKeyAlgorithm() const
383 {
384     return subkey ? static_cast<PubkeyAlgo>(subkey->pubkey_algo) : AlgoUnknown;
385 }
386
387 const char *Subkey::publicKeyAlgorithmAsString() const
388 {
389     return gpgme_pubkey_algo_name(subkey ? subkey->pubkey_algo : (gpgme_pubkey_algo_t)0);
390 }
391
392 /* static */
393 const char *Subkey::publicKeyAlgorithmAsString(PubkeyAlgo algo)
394 {
395     if (algo == AlgoUnknown) {
396         return NULL;
397     }
398     return gpgme_pubkey_algo_name(static_cast<gpgme_pubkey_algo_t>(algo));
399 }
400
401 std::string Subkey::algoName() const
402 {
403     char *gpgmeStr;
404     if (subkey && (gpgmeStr = gpgme_pubkey_algo_string(subkey))) {
405         std::string ret = std::string(gpgmeStr);
406         gpgme_free(gpgmeStr);
407         return ret;
408     }
409     return std::string();
410 }
411
412 bool Subkey::canEncrypt() const
413 {
414     return subkey && subkey->can_encrypt;
415 }
416
417 bool Subkey::canSign() const
418 {
419     return subkey && subkey->can_sign;
420 }
421
422 bool Subkey::canCertify() const
423 {
424     return subkey && subkey->can_certify;
425 }
426
427 bool Subkey::canAuthenticate() const
428 {
429     return subkey && subkey->can_authenticate;
430 }
431
432 bool Subkey::isQualified() const
433 {
434     return subkey && subkey->is_qualified;
435 }
436
437 bool Subkey::isCardKey() const
438 {
439     return subkey && subkey->is_cardkey;
440 }
441
442 const char *Subkey::cardSerialNumber() const
443 {
444     return subkey ? subkey->card_number : 0 ;
445 }
446
447 bool Subkey::isSecret() const
448 {
449     return subkey && subkey->secret;
450 }
451
452 unsigned int Subkey::length() const
453 {
454     return subkey ? subkey->length : 0 ;
455 }
456
457 time_t Subkey::creationTime() const
458 {
459     return static_cast<time_t>(subkey ? subkey->timestamp : 0);
460 }
461
462 time_t Subkey::expirationTime() const
463 {
464     return static_cast<time_t>(subkey ? subkey->expires : 0);
465 }
466
467 bool Subkey::neverExpires() const
468 {
469     return expirationTime() == time_t(0);
470 }
471
472 bool Subkey::isRevoked() const
473 {
474     return subkey && subkey->revoked;
475 }
476
477 bool Subkey::isInvalid() const
478 {
479     return subkey && subkey->invalid;
480 }
481
482 bool Subkey::isExpired() const
483 {
484     return subkey && subkey->expired;
485 }
486
487 bool Subkey::isDisabled() const
488 {
489     return subkey && subkey->disabled;
490 }
491
492 //
493 //
494 // class UserID
495 //
496 //
497
498 gpgme_user_id_t find_uid(const shared_gpgme_key_t &key, unsigned int idx)
499 {
500     if (key) {
501         for (gpgme_user_id_t u = key->uids ; u ; u = u->next, --idx) {
502             if (idx == 0) {
503                 return u;
504             }
505         }
506     }
507     return 0;
508 }
509
510 gpgme_user_id_t verify_uid(const shared_gpgme_key_t &key, gpgme_user_id_t uid)
511 {
512     if (key) {
513         for (gpgme_user_id_t u = key->uids ; u ; u = u->next) {
514             if (u == uid) {
515                 return uid;
516             }
517         }
518     }
519     return 0;
520 }
521
522 UserID::UserID() : key(), uid(0) {}
523
524 UserID::UserID(const shared_gpgme_key_t &k, gpgme_user_id_t u)
525     : key(k), uid(verify_uid(k, u))
526 {
527
528 }
529
530 UserID::UserID(const shared_gpgme_key_t &k, unsigned int idx)
531     : key(k), uid(find_uid(k, idx))
532 {
533
534 }
535
536 Key UserID::parent() const
537 {
538     return Key(key);
539 }
540
541 UserID::Signature UserID::signature(unsigned int index) const
542 {
543     return Signature(key, uid, index);
544 }
545
546 unsigned int UserID::numSignatures() const
547 {
548     if (!uid) {
549         return 0;
550     }
551     unsigned int count = 0;
552     for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) {
553         ++count;
554     }
555     return count;
556 }
557
558 std::vector<UserID::Signature> UserID::signatures() const
559 {
560     if (!uid) {
561         return std::vector<Signature>();
562     }
563
564     std::vector<Signature> v;
565     v.reserve(numSignatures());
566     for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) {
567         v.push_back(Signature(key, uid, sig));
568     }
569     return v;
570 }
571
572 const char *UserID::id() const
573 {
574     return uid ? uid->uid : 0 ;
575 }
576
577 const char *UserID::name() const
578 {
579     return uid ? uid->name : 0 ;
580 }
581
582 const char *UserID::email() const
583 {
584     return uid ? uid->email : 0 ;
585 }
586
587 const char *UserID::comment() const
588 {
589     return uid ? uid->comment : 0 ;
590 }
591
592 UserID::Validity UserID::validity() const
593 {
594     if (!uid) {
595         return Unknown;
596     }
597     switch (uid->validity) {
598     default:
599     case GPGME_VALIDITY_UNKNOWN:   return Unknown;
600     case GPGME_VALIDITY_UNDEFINED: return Undefined;
601     case GPGME_VALIDITY_NEVER:     return Never;
602     case GPGME_VALIDITY_MARGINAL:  return Marginal;
603     case GPGME_VALIDITY_FULL:      return Full;
604     case GPGME_VALIDITY_ULTIMATE:  return Ultimate;
605     }
606 }
607
608 char UserID::validityAsString() const
609 {
610     if (!uid) {
611         return '?';
612     }
613     switch (uid->validity) {
614     default:
615     case GPGME_VALIDITY_UNKNOWN:   return '?';
616     case GPGME_VALIDITY_UNDEFINED: return 'q';
617     case GPGME_VALIDITY_NEVER:     return 'n';
618     case GPGME_VALIDITY_MARGINAL:  return 'm';
619     case GPGME_VALIDITY_FULL:      return 'f';
620     case GPGME_VALIDITY_ULTIMATE:  return 'u';
621     }
622 }
623
624 bool UserID::isRevoked() const
625 {
626     return uid && uid->revoked;
627 }
628
629 bool UserID::isInvalid() const
630 {
631     return uid && uid->invalid;
632 }
633
634 TofuInfo UserID::tofuInfo() const
635 {
636     if (!uid) {
637         return TofuInfo();
638     }
639     return TofuInfo(uid->tofu);
640 }
641
642 //
643 //
644 // class Signature
645 //
646 //
647
648 gpgme_key_sig_t find_signature(gpgme_user_id_t uid, unsigned int idx)
649 {
650     if (uid) {
651         for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next, --idx) {
652             if (idx == 0) {
653                 return s;
654             }
655         }
656     }
657     return 0;
658 }
659
660 gpgme_key_sig_t verify_signature(gpgme_user_id_t uid, gpgme_key_sig_t sig)
661 {
662     if (uid) {
663         for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next) {
664             if (s == sig) {
665                 return sig;
666             }
667         }
668     }
669     return 0;
670 }
671
672 UserID::Signature::Signature() : key(), uid(0), sig(0) {}
673
674 UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, unsigned int idx)
675     : key(k), uid(verify_uid(k, u)), sig(find_signature(uid, idx))
676 {
677
678 }
679
680 UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, gpgme_key_sig_t s)
681     : key(k), uid(verify_uid(k, u)), sig(verify_signature(uid, s))
682 {
683
684 }
685
686 UserID UserID::Signature::parent() const
687 {
688     return UserID(key, uid);
689 }
690
691 const char *UserID::Signature::signerKeyID() const
692 {
693     return sig ? sig->keyid : 0 ;
694 }
695
696 const char *UserID::Signature::algorithmAsString() const
697 {
698     return gpgme_pubkey_algo_name(sig ? sig->pubkey_algo : (gpgme_pubkey_algo_t)0);
699 }
700
701 unsigned int UserID::Signature::algorithm() const
702 {
703     return sig ? sig->pubkey_algo : 0 ;
704 }
705
706 time_t UserID::Signature::creationTime() const
707 {
708     return static_cast<time_t>(sig ? sig->timestamp : 0);
709 }
710
711 time_t UserID::Signature::expirationTime() const
712 {
713     return static_cast<time_t>(sig ? sig->expires : 0);
714 }
715
716 bool UserID::Signature::neverExpires() const
717 {
718     return expirationTime() == time_t(0);
719 }
720
721 bool UserID::Signature::isRevokation() const
722 {
723     return sig && sig->revoked;
724 }
725
726 bool UserID::Signature::isInvalid() const
727 {
728     return sig && sig->invalid;
729 }
730
731 bool UserID::Signature::isExpired() const
732 {
733     return sig && sig->expired;
734 }
735
736 bool UserID::Signature::isExportable() const
737 {
738     return sig && sig->exportable;
739 }
740
741 const char *UserID::Signature::signerUserID() const
742 {
743     return sig ? sig->uid : 0 ;
744 }
745
746 const char *UserID::Signature::signerName() const
747 {
748     return sig ? sig->name : 0 ;
749 }
750
751 const char *UserID::Signature::signerEmail() const
752 {
753     return sig ? sig->email : 0 ;
754 }
755
756 const char *UserID::Signature::signerComment() const
757 {
758     return sig ? sig->comment : 0 ;
759 }
760
761 unsigned int UserID::Signature::certClass() const
762 {
763     return sig ? sig->sig_class : 0 ;
764 }
765
766 UserID::Signature::Status UserID::Signature::status() const
767 {
768     if (!sig) {
769         return GeneralError;
770     }
771
772     switch (gpgme_err_code(sig->status)) {
773     case GPG_ERR_NO_ERROR:      return NoError;
774     case GPG_ERR_SIG_EXPIRED:   return SigExpired;
775     case GPG_ERR_KEY_EXPIRED:   return KeyExpired;
776     case GPG_ERR_BAD_SIGNATURE: return BadSignature;
777     case GPG_ERR_NO_PUBKEY:     return NoPublicKey;
778     default:
779     case GPG_ERR_GENERAL:       return GeneralError;
780     }
781 }
782
783 std::string UserID::Signature::statusAsString() const
784 {
785     if (!sig) {
786         return std::string();
787     }
788     char buf[ 1024 ];
789     gpgme_strerror_r(sig->status, buf, sizeof buf);
790     buf[ sizeof buf - 1 ] = '\0';
791     return std::string(buf);
792 }
793
794 GpgME::Notation UserID::Signature::notation(unsigned int idx) const
795 {
796     if (!sig) {
797         return GpgME::Notation();
798     }
799     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
800         if (nota->name) {
801             if (idx-- == 0) {
802                 return GpgME::Notation(nota);
803             }
804         }
805     }
806     return GpgME::Notation();
807 }
808
809 unsigned int UserID::Signature::numNotations() const
810 {
811     if (!sig) {
812         return 0;
813     }
814     unsigned int count = 0;
815     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
816         if (nota->name) {
817             ++count; // others are policy URLs...
818         }
819     }
820     return count;
821 }
822
823 std::vector<Notation> UserID::Signature::notations() const
824 {
825     if (!sig) {
826         return std::vector<GpgME::Notation>();
827     }
828     std::vector<GpgME::Notation> v;
829     v.reserve(numNotations());
830     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
831         if (nota->name) {
832             v.push_back(GpgME::Notation(nota));
833         }
834     }
835     return v;
836 }
837
838 const char *UserID::Signature::policyURL() const
839 {
840     if (!sig) {
841         return 0;
842     }
843     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
844         if (!nota->name) {
845             return nota->value;
846         }
847     }
848     return 0;
849 }
850
851 } // namespace GpgME