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