Fix copyright year.
[gpgme.git] / gpgme / key.c
1 /* key.c - Key objects.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003 g10 Code GmbH
4
5    This file is part of GPGME.
6  
7    GPGME is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11  
12    GPGME is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16  
17    You should have received a copy of the GNU General Public License
18    along with GPGME; if not, write to the Free Software Foundation,
19    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <ctype.h>
29
30 #include "util.h"
31 #include "ops.h"
32 #include "key.h"
33 #include "sema.h"
34
35 #if SIZEOF_UNSIGNED_INT < 4
36 #error unsigned int too short to be used as a hash value
37 #endif
38
39 \f
40 struct key_cache_item_s
41 {
42   struct key_cache_item_s *next;
43   GpgmeKey key;
44 };
45
46 /* Protects all key_cache_* variables.  */
47 DEFINE_STATIC_LOCK (key_cache_lock);
48 static int key_cache_initialized;
49 static struct key_cache_item_s **key_cache;
50 static size_t key_cache_size;
51 static size_t key_cache_max_chain_length;
52 static struct key_cache_item_s *key_cache_unused_items;
53
54 /* Protects all reference counters in keys.  All other accesses to a
55    key are either read only or happen before the key is entered into
56    the cache.  */
57 DEFINE_STATIC_LOCK (key_ref_lock);
58
59 static int
60 hash_key (const char *fpr, unsigned int *rhash)
61 {
62   unsigned int hash;
63   int c;
64
65   if (!fpr)
66     return -1;
67   if ((c = _gpgme_hextobyte (fpr)) == -1)
68     return -1;
69   hash = c;
70   if ((c = _gpgme_hextobyte (fpr+2)) == -1)
71     return -1;
72   hash |= c << 8;
73   if ((c = _gpgme_hextobyte (fpr+4)) == -1)
74     return -1;
75   hash |= c << 16;
76   if ((c = _gpgme_hextobyte (fpr+6)) == -1)
77     return -1;
78   hash |= c << 24;
79
80   *rhash = hash;
81   return 0;
82 }
83
84
85 void
86 _gpgme_key_cache_init (void)
87 {
88   LOCK (key_cache_lock);
89   if (!key_cache_initialized)
90     {
91       key_cache_size = 503;
92       key_cache = calloc (key_cache_size, sizeof *key_cache);
93       if (!key_cache)
94         {
95           key_cache_size = 0;
96           key_cache_initialized = 1;
97         }
98       else
99         {
100           /* The upper bound for our cache size is
101              key_cache_max_chain_length * key_cache_size.  */
102           key_cache_max_chain_length = 10;
103           key_cache_initialized = 1;
104         }
105     }
106   UNLOCK (key_cache_lock);
107 }
108
109
110 void
111 _gpgme_key_cache_add (GpgmeKey key)
112 {
113   struct subkey_s *k;
114
115   if (!key)
116     return;
117
118   _gpgme_key_cache_init ();
119
120   LOCK (key_cache_lock);
121   /* Check if cache was enabled.  */
122   if (!key_cache_size)
123     {
124       UNLOCK (key_cache_lock);
125       return;
126     }
127
128   /* Put the key under each fingerprint into the cache.  We use the
129      first 4 digits to calculate the hash.  */
130   for (k = &key->keys; k; k = k->next)
131     {
132       size_t n;
133       unsigned int hash;
134       struct key_cache_item_s *item;
135
136       if (hash_key (k->fingerprint, &hash))
137         continue;
138
139       hash %= key_cache_size;
140       for (item = key_cache[hash], n=0; item; item = item->next, n++)
141         {
142           struct subkey_s *k2;
143           if (item->key == key) 
144             /* Already in cache.  */
145             break;
146           /* Now do a deeper check.  */
147           for (k2 = &item->key->keys; k2; k2 = k2->next)
148             {
149               if (k2->fingerprint && !strcmp (k->fingerprint, k2->fingerprint))
150                 {
151                   /* Okay, replace it with the new copy.  */
152                   gpgme_key_unref (item->key);
153                   item->key = key;
154                   gpgme_key_ref (item->key);
155                   UNLOCK (key_cache_lock);
156                   return;
157                 }
158             }
159         }
160       if (item)
161         continue;
162         
163       if (n > key_cache_max_chain_length)
164         {
165           /* Remove the last entries.  */
166           struct key_cache_item_s *last = NULL;
167
168           for (item = key_cache[hash];
169                item && n < key_cache_max_chain_length;
170                last = item, item = item->next, n++)
171             ;
172           
173           if (last)
174             {
175               struct key_cache_item_s *next;
176
177               assert (last->next == item);
178               last->next = NULL;
179               for (; item; item = next)
180                 {
181                   next = item->next;
182                   gpgme_key_unref (item->key);
183                   item->key = NULL;
184                   item->next = key_cache_unused_items;
185                   key_cache_unused_items = item;
186                 }
187             }
188         }
189
190       item = key_cache_unused_items;
191       if (item)
192         {
193           key_cache_unused_items = item->next;
194           item->next = NULL;
195         }
196       else
197         {
198           item = malloc (sizeof *item);
199           if (!item)
200             {
201               UNLOCK (key_cache_lock);
202               return;
203             }
204         }
205
206       item->key = key;
207       gpgme_key_ref (key);
208       item->next = key_cache[hash];
209       key_cache[hash] = item;
210     }
211   UNLOCK (key_cache_lock);
212 }
213
214
215 GpgmeKey 
216 _gpgme_key_cache_get (const char *fpr)
217 {
218   struct key_cache_item_s *item;
219   unsigned int hash;
220
221   LOCK (key_cache_lock);
222   /* Check if cache is enabled already.  */
223   if (!key_cache_size)
224     {
225       UNLOCK (key_cache_lock);
226       return NULL;
227     }
228
229   if (hash_key (fpr, &hash))
230     {
231       UNLOCK (key_cache_lock);
232       return NULL;
233     }
234
235   hash %= key_cache_size;
236   for (item = key_cache[hash]; item; item = item->next)
237     {
238       struct subkey_s *k;
239
240       for (k = &item->key->keys; k; k = k->next)
241         {
242           if (k->fingerprint && !strcmp (k->fingerprint, fpr))
243             {
244               gpgme_key_ref (item->key);
245               UNLOCK (key_cache_lock);
246               return item->key;
247             }
248         }
249     }
250   UNLOCK (key_cache_lock);
251   return NULL;
252 }
253
254 \f
255 static const char *
256 pkalgo_to_string (int algo)
257 {
258   switch (algo)
259     {
260     case 1: 
261     case 2:
262     case 3:
263       return "RSA";
264
265     case 16:
266     case 20:
267       return "ElG";
268
269     case 17:
270       return "DSA";
271
272     default:
273       return "Unknown";
274     }
275 }
276
277
278 static const char *
279 otrust_to_string (int otrust)
280 {
281   switch (otrust)
282     {
283     case GPGME_VALIDITY_NEVER:
284       return "n";
285
286     case GPGME_VALIDITY_MARGINAL:
287       return "m";
288
289     case GPGME_VALIDITY_FULL:
290       return "f";
291
292     case GPGME_VALIDITY_ULTIMATE:
293       return "u";
294
295     default:
296       return "?";
297     }
298 }
299
300
301 static const char *
302 validity_to_string (int validity)
303 {
304   switch (validity)
305     {
306     case GPGME_VALIDITY_UNDEFINED:
307       return "q";
308
309     case GPGME_VALIDITY_NEVER:
310       return "n";
311
312     case GPGME_VALIDITY_MARGINAL:
313       return "m";
314
315     case GPGME_VALIDITY_FULL:
316       return "f";
317
318     case GPGME_VALIDITY_ULTIMATE:
319       return "u";
320
321     case GPGME_VALIDITY_UNKNOWN:
322     default:
323       return "?";
324     }
325 }
326
327
328 static GpgmeError
329 key_new (GpgmeKey *r_key, int secret)
330 {
331   GpgmeKey key;
332
333   *r_key = NULL;
334   key = calloc (1, sizeof *key);
335   if (!key)
336     return GPGME_Out_Of_Core;
337   key->ref_count = 1;
338   *r_key = key;
339   if (secret)
340     key->secret = 1;
341   return 0;
342 }
343
344
345 GpgmeError
346 _gpgme_key_new (GpgmeKey *r_key)
347 {
348   return key_new (r_key, 0);
349 }
350
351
352 GpgmeError
353 _gpgme_key_new_secret (GpgmeKey *r_key)
354 {
355   return key_new (r_key, 1);
356 }
357
358
359 /**
360  * gpgme_key_ref:
361  * @key: Key object
362  * 
363  * To safe memory the Key objects implements reference counting.
364  * Use this function to bump the reference counter.
365  **/
366 void
367 gpgme_key_ref (GpgmeKey key)
368 {
369   return_if_fail (key);
370   LOCK (key_ref_lock);
371   key->ref_count++;
372   UNLOCK (key_ref_lock);
373 }
374
375 \f
376 static struct subkey_s *
377 add_subkey (GpgmeKey key, int secret)
378 {
379   struct subkey_s *k, *kk;
380
381   k = calloc (1, sizeof *k);
382   if (!k)
383     return NULL;
384
385   if (!(kk = key->keys.next))
386     key->keys.next = k;
387   else
388     {
389       while (kk->next)
390         kk = kk->next;
391       kk->next = k;
392     }
393   if (secret)
394     k->secret = 1;
395   return k;
396 }
397
398
399 struct subkey_s *
400 _gpgme_key_add_subkey (GpgmeKey key)
401 {
402   return add_subkey (key, 0);
403 }
404
405
406 struct subkey_s *
407 _gpgme_key_add_secret_subkey (GpgmeKey key)
408 {
409   return add_subkey (key, 1);
410 }
411
412 \f
413 static char *
414 set_user_id_part (char *tail, const char *buf, size_t len)
415 {
416   while (len && (buf[len - 1] == ' ' || buf[len - 1] == '\t')) 
417     len--;
418   for (; len; len--)
419     *tail++ = *buf++;
420   *tail++ = 0;
421   return tail;
422 }
423
424
425 static void
426 parse_user_id (const char *src, const char **name, const char **email,
427                     const char **comment, char *tail)
428 {
429   const char *start = NULL;
430   int in_name = 0;
431   int in_email = 0;
432   int in_comment = 0;
433
434   while (*src)
435     {
436       if (in_email)
437         {
438           if (*src == '<')
439             /* Not legal but anyway.  */
440             in_email++;
441           else if (*src == '>')
442             {
443               if (!--in_email && !*email)
444                 {
445                   *email = tail;
446                   tail = set_user_id_part (tail, start, src - start);
447                 }
448             }
449         }
450       else if (in_comment)
451         {
452           if (*src == '(')
453             in_comment++;
454           else if (*src == ')')
455             {
456               if (!--in_comment && !*comment)
457                 {
458                   *comment = tail;
459                   tail = set_user_id_part (tail, start, src - start);
460                 }
461             }
462         }
463       else if (*src == '<')
464         {
465           if (in_name)
466             {
467               if (!*name)
468                 {
469                   *name = tail;
470                   tail = set_user_id_part (tail, start, src - start);
471                 }
472               in_name = 0;
473             }
474           in_email = 1;
475           start = src + 1;
476         }
477       else if (*src == '(')
478         {
479           if (in_name)
480             {
481               if (!*name)
482                 {
483                   *name = tail;
484                   tail = set_user_id_part (tail, start, src - start);
485                 }
486               in_name = 0;
487             }
488           in_comment = 1;
489           start = src + 1;
490         }
491       else if (!in_name && *src != ' ' && *src != '\t')
492         {
493           in_name = 1;
494           start = src;
495         }    
496       src++;
497     }
498  
499   if (in_name)
500     {
501       if (!*name)
502         {
503           *name = tail;
504           tail = set_user_id_part (tail, start, src - start);
505         }
506     }
507  
508   /* Let unused parts point to an EOS.  */
509   tail--;
510   if (!*name)
511     *name = tail;
512   if (!*email)
513     *email = tail;
514   if (!*comment)
515     *comment = tail;
516 }
517
518
519 static void
520 parse_x509_user_id (const char *src, const char **name, const char **email,
521                     const char **comment, char *tail)
522 {
523   if (*src == '<' && src[strlen (src) - 1] == '>')
524     *email = src;
525   
526   /* Let unused parts point to an EOS.  */
527   tail--;
528   if (!*name)
529     *name = tail;
530   if (!*email)
531     *email = tail;
532   if (!*comment)
533     *comment = tail;
534 }
535
536 \f
537 struct certsig_s *
538 _gpgme_key_add_certsig (GpgmeKey key, char *src)
539 {
540   int src_len = src ? strlen (src) : 0;
541   struct user_id_s *uid;
542   struct certsig_s *certsig;
543
544   assert (key); /* XXX */
545
546   uid = key->last_uid;
547   assert (uid); /* XXX */
548
549   /* We can malloc a buffer of the same length, because the converted
550      string will never be larger. Actually we allocate it twice the
551      size, so that we are able to store the parsed stuff there too.  */
552   certsig = calloc (1, sizeof (*certsig) + 2 * src_len + 3);
553   if (!certsig)
554     return NULL;
555
556   if (src)
557     {
558       char *dst = certsig->name;
559       _gpgme_decode_c_string (src, &dst, src_len + 1);
560       dst += src_len + 1;
561       if (key->x509)
562         parse_x509_user_id (src, &certsig->name_part, &certsig->email_part,
563                             &certsig->comment_part, dst);
564       else
565         parse_user_id (src, &certsig->name_part, &certsig->email_part,
566                        &certsig->comment_part, dst);
567     }
568
569   if (!uid->certsigs)
570     uid->certsigs = certsig;
571   if (uid->last_certsig)
572     uid->last_certsig->next = certsig;
573   uid->last_certsig = certsig;
574
575   return certsig;
576 }
577
578 \f
579 /**
580  * gpgme_key_release:
581  * @key: Key Object or NULL
582  * 
583  * Release the key object. Note, that this function may not do an
584  * actual release if there are other shallow copies of the objects.
585  * You have to call this function for every newly created key object
586  * as well as for every gpgme_key_ref() done on the key object.
587  **/
588 void
589 gpgme_key_release (GpgmeKey key)
590 {
591   struct certsig_s *c, *c2;
592   struct user_id_s *u, *u2;
593   struct subkey_s *k, *k2;
594
595   if (!key)
596     return;
597
598   LOCK (key_ref_lock);
599   assert (key->ref_count);
600   if (--key->ref_count)
601     {
602       UNLOCK (key_ref_lock);
603       return;
604     }
605   UNLOCK (key_ref_lock);
606
607   free (key->keys.fingerprint);
608   for (k = key->keys.next; k; k = k2)
609     {
610       k2 = k->next;
611       free (k->fingerprint);
612       free (k);
613     }
614   for (u = key->uids; u; u = u2)
615     {
616       u2 = u->next;
617       for (c = u->certsigs; c; c = c2)
618         {
619           c2 = c->next;
620           free (c);
621         }
622       free (u);
623     }
624   free (key->issuer_serial);
625   free (key->issuer_name);
626   free (key->chain_id);
627   free (key);
628 }
629
630
631 /**
632  * gpgme_key_unref:
633  * @key: Key Object
634  * 
635  * This is an alias for gpgme_key_release().
636  **/
637 void
638 gpgme_key_unref (GpgmeKey key)
639 {
640   gpgme_key_release (key);
641 }
642
643 \f
644 /* Take a name from the --with-colon listing, remove certain escape
645    sequences sequences and put it into the list of UIDs.  */
646 GpgmeError
647 _gpgme_key_append_name (GpgmeKey key, const char *src)
648 {
649   struct user_id_s *uid;
650   char *dst;
651   int src_len = strlen (src);
652
653   assert (key);
654   /* We can malloc a buffer of the same length, because the converted
655      string will never be larger. Actually we allocate it twice the
656      size, so that we are able to store the parsed stuff there too.  */
657   uid = malloc (sizeof (*uid) + 2 * src_len + 3);
658   if (!uid)
659     return GPGME_Out_Of_Core;
660   memset (uid, 0, sizeof *uid);
661
662   dst = uid->name;
663   _gpgme_decode_c_string (src, &dst, src_len + 1);
664
665   dst += src_len + 1;
666   if (key->x509)
667     parse_x509_user_id (src, &uid->name_part, &uid->email_part,
668                         &uid->comment_part, dst);
669   else
670     parse_user_id (src, &uid->name_part, &uid->email_part,
671                    &uid->comment_part, dst);
672
673   if (!key->uids)
674     key->uids = uid;
675   if (key->last_uid)
676     key->last_uid->next = uid;
677   key->last_uid = uid;
678
679   return 0;
680 }
681
682
683 static void
684 add_otag (GpgmeData d, const char *tag)
685 {
686   _gpgme_data_append_string (d, "    <");
687   _gpgme_data_append_string (d, tag);
688   _gpgme_data_append_string (d, ">");
689 }
690
691
692 static void
693 add_ctag (GpgmeData d, const char *tag)
694 {
695   _gpgme_data_append_string (d, "</");
696   _gpgme_data_append_string (d, tag);
697   _gpgme_data_append_string (d, ">\n");
698 }
699
700
701 static void
702 add_tag_and_string (GpgmeData d, const char *tag, const char *string)
703 {
704   add_otag (d, tag);
705   _gpgme_data_append_string_for_xml (d, string);
706   add_ctag (d, tag); 
707 }
708
709
710 static void
711 add_tag_and_uint (GpgmeData d, const char *tag, unsigned int val)
712 {
713   char buf[30];
714   sprintf (buf, "%u", val);
715   add_tag_and_string (d, tag, buf);
716 }
717
718
719 static void
720 add_tag_and_time (GpgmeData d, const char *tag, time_t val)
721 {
722   char buf[30];
723
724   if (!val || val == (time_t) - 1)
725     return;
726   sprintf (buf, "%lu", (unsigned long) val);
727   add_tag_and_string (d, tag, buf);
728 }
729
730
731 static void
732 one_certsig_as_xml (GpgmeData data, struct certsig_s *certsig)
733 {
734   _gpgme_data_append_string (data, "    <signature>\n");
735   if (certsig->flags.invalid)
736     _gpgme_data_append_string (data, "      <invalid/>\n");
737   if (certsig->flags.revoked)
738     _gpgme_data_append_string (data, "      <revoked/>\n");
739   if (certsig->flags.expired)
740     _gpgme_data_append_string (data, "      <expired/>\n");
741   add_tag_and_string (data, "keyid", certsig->keyid);
742   add_tag_and_uint (data, "algo", certsig->algo);
743   add_tag_and_time (data, "created", certsig->timestamp);
744   add_tag_and_time (data, "expire", certsig->expires_at);
745   if (*certsig->name)
746     add_tag_and_string (data, "raw", certsig->name);
747   if (*certsig->name_part)
748     add_tag_and_string (data, "name", certsig->name_part);
749   if (*certsig->email_part)
750     add_tag_and_string (data, "email", certsig->email_part);
751   if (*certsig->comment_part)
752     add_tag_and_string (data, "comment", certsig->comment_part);
753   _gpgme_data_append_string (data, "    </signature>\n");
754 }
755
756
757 static void
758 one_uid_as_xml (GpgmeData data, struct user_id_s *uid)
759 {
760   struct certsig_s *certsig;
761
762   _gpgme_data_append_string (data, "  <userid>\n");
763   if (uid->invalid)
764     _gpgme_data_append_string (data, "    <invalid/>\n");
765   if (uid->revoked)
766     _gpgme_data_append_string (data, "    <revoked/>\n");
767   add_tag_and_string (data, "raw", uid->name);
768   if (*uid->name_part)
769     add_tag_and_string (data, "name", uid->name_part);
770   if (*uid->email_part)
771     add_tag_and_string (data, "email", uid->email_part);
772   if (*uid->comment_part)
773     add_tag_and_string (data, "comment", uid->comment_part);
774
775   /* Now the signatures.  */
776   for (certsig = uid->certsigs; certsig; certsig = certsig->next)
777     one_certsig_as_xml (data, certsig);
778   _gpgme_data_append_string (data, "  </userid>\n");
779 }
780
781
782 /**
783  * gpgme_key_get_as_xml:
784  * @key: Key object
785  * 
786  * Return the key object as an XML string.  The classer has to free
787  * that string.
788  * 
789  * Return value:  An XML string or NULL in case of a memory problem or
790  *                a NULL passed as @key
791  **/
792 char *
793 gpgme_key_get_as_xml (GpgmeKey key)
794 {
795   GpgmeData d;
796   struct user_id_s *u;
797   struct subkey_s *k;
798   
799   if (!key)
800     return NULL;
801   
802   if (gpgme_data_new (&d))
803     return NULL;
804   
805   _gpgme_data_append_string (d, "<GnupgKeyblock>\n"
806                              "  <mainkey>\n");
807   if (key->keys.secret)
808     _gpgme_data_append_string (d, "    <secret/>\n");
809   if (key->keys.flags.invalid)
810     _gpgme_data_append_string (d, "    <invalid/>\n");
811   if (key->keys.flags.revoked)
812     _gpgme_data_append_string (d, "    <revoked/>\n");
813   if (key->keys.flags.expired)
814     _gpgme_data_append_string (d, "    <expired/>\n");
815   if (key->keys.flags.disabled)
816     _gpgme_data_append_string (d, "    <disabled/>\n");
817   add_tag_and_string (d, "keyid", key->keys.keyid);
818   if (key->keys.fingerprint)
819     add_tag_and_string (d, "fpr", key->keys.fingerprint);
820   add_tag_and_uint (d, "algo", key->keys.key_algo);
821   add_tag_and_uint (d, "len", key->keys.key_len);
822   add_tag_and_time (d, "created", key->keys.timestamp);
823   add_tag_and_time (d, "expire", key->keys.expires_at);
824   add_tag_and_string (d, "otrust", otrust_to_string (key->otrust));
825   if (key->issuer_serial)
826     add_tag_and_string (d, "serial", key->issuer_serial);
827   if (key->issuer_name)
828     add_tag_and_string (d, "issuer", key->issuer_name);
829   if (key->chain_id)
830     add_tag_and_string (d, "chainid", key->chain_id);
831   _gpgme_data_append_string (d, "  </mainkey>\n");
832
833   /* Now the user IDs.  */
834   for (u = key->uids; u; u = u->next)
835     one_uid_as_xml (d,u);
836   
837   /* And now the subkeys.  */
838   for (k = key->keys.next; k; k = k->next)
839     {
840       _gpgme_data_append_string (d, "  <subkey>\n");
841       if (k->secret)
842         _gpgme_data_append_string (d, "    <secret/>\n");
843       if (k->flags.invalid)
844         _gpgme_data_append_string (d, "    <invalid/>\n");
845       if (k->flags.revoked)
846         _gpgme_data_append_string (d, "    <revoked/>\n");
847       if (k->flags.expired)
848         _gpgme_data_append_string (d, "    <expired/>\n");
849       if (k->flags.disabled)
850         _gpgme_data_append_string (d, "    <disabled/>\n");
851       add_tag_and_string (d, "keyid", k->keyid);
852       if (k->fingerprint)
853         add_tag_and_string (d, "fpr", k->fingerprint);
854       add_tag_and_uint (d, "algo", k->key_algo);
855       add_tag_and_uint (d, "len", k->key_len);
856       add_tag_and_time (d, "created", k->timestamp);
857       add_tag_and_time (d, "expire", k->expires_at);
858       _gpgme_data_append_string (d, "  </subkey>\n");
859     }
860   _gpgme_data_append_string (d, "</GnupgKeyblock>\n");
861   
862   return _gpgme_data_release_and_return_string (d);
863 }
864
865
866 static const char *
867 capabilities_to_string (struct subkey_s *k)
868 {
869   static const char *const strings[8] =
870     {
871       "",
872       "c",
873       "s",
874       "sc",
875       "e",
876       "ec",
877       "es",
878       "esc"
879     };
880   return strings[(!!k->flags.can_encrypt << 2)
881                  | (!!k->flags.can_sign << 1)
882                  | (!!k->flags.can_certify)];
883 }
884
885
886 /**
887  * gpgme_key_get_string_attr:
888  * @key: Key Object
889  * @what: Attribute specifier
890  * @reserved: Must be 0
891  * @idx: Index counter
892  * 
893  * Return a attribute as specified by @what and @idx.  Note that not
894  * all attributes can be returned as a string, in which case NULL is
895  * returned.  @idx is used to iterate through attributes which do have
896  * more than one instance (e.g. user IDs or sub keys).
897  * 
898  * Return value: NULL or an const string which is only valid as long
899  * as the key object itself is valid.
900  **/
901 const char *
902 gpgme_key_get_string_attr (GpgmeKey key, GpgmeAttr what,
903                            const void *reserved, int idx)
904 {
905   struct subkey_s *subkey;
906   struct user_id_s *uid;
907   int i;
908
909   if (!key || reserved || idx < 0)
910     return NULL;
911
912   /* Select IDXth subkey.  */
913   subkey = &key->keys;
914   for (i = 0; i < idx; i++)
915     {
916       subkey = subkey->next;
917       if (!subkey)
918         break;
919     }
920
921   /* Select the IDXth user ID.  */
922   uid = key->uids;
923   for (i = 0; i < idx; i++)
924     {
925       uid = uid->next;
926       if (!uid)
927         break;
928     }
929
930   switch (what)
931     {
932     case GPGME_ATTR_KEYID:
933       return subkey ? subkey->keyid : NULL;
934
935     case GPGME_ATTR_FPR:
936       return subkey ? subkey->fingerprint : NULL;
937
938     case GPGME_ATTR_ALGO:    
939       return subkey ? pkalgo_to_string (subkey->key_algo) : NULL;
940
941     case GPGME_ATTR_TYPE:
942       return key->x509 ? "X.509" : "PGP";
943
944     case GPGME_ATTR_OTRUST:
945       return otrust_to_string (key->otrust);
946
947     case GPGME_ATTR_USERID:  
948       return uid ? uid->name : NULL;
949
950     case GPGME_ATTR_NAME:   
951       return uid ? uid->name_part : NULL;
952
953     case GPGME_ATTR_EMAIL:
954       return uid ? uid->email_part : NULL;
955
956     case GPGME_ATTR_COMMENT:
957       return uid ? uid->comment_part : NULL;
958
959     case GPGME_ATTR_VALIDITY:
960       return validity_to_string (key->otrust);
961
962     case GPGME_ATTR_KEY_CAPS:    
963       return subkey ? capabilities_to_string (subkey) : NULL;
964
965     case GPGME_ATTR_SERIAL:
966       return key->issuer_serial;
967
968     case GPGME_ATTR_ISSUER:
969       return idx ? NULL : key->issuer_name;
970
971     case GPGME_ATTR_CHAINID:
972       return  key->chain_id;
973
974     default:
975       return NULL;
976     }
977 }
978
979
980 /**
981  * gpgme_key_get_ulong_attr:
982  * @key: 
983  * @what: 
984  * @reserved: 
985  * @idx: 
986  * 
987  * Return a attribute as specified by @what and @idx.  Note that not
988  * all attributes can be returned as an integer, in which case 0 is
989  * returned.  @idx is used to iterate through attributes which do have
990  * more than one instance (e.g. user IDs or sub keys).
991  *
992  * See gpgme.h for a list of attributes.
993  * 
994  * Return value: 0 or the requested value.
995  **/
996 unsigned long
997 gpgme_key_get_ulong_attr (GpgmeKey key, GpgmeAttr what,
998                           const void *reserved, int idx)
999 {
1000   struct subkey_s *subkey;
1001   struct user_id_s *uid;
1002   int i;
1003
1004   if (!key || reserved || idx < 0)
1005     return 0;
1006
1007   /* Select IDXth subkey.  */
1008   subkey = &key->keys;
1009   for (i = 0; i < idx; i++)
1010     {
1011       subkey = subkey->next;
1012       if (!subkey)
1013         break;
1014     }
1015
1016   /* Select the IDXth user ID.  */
1017   uid = key->uids;
1018   for (i = 0; i < idx; i++)
1019     {
1020       uid = uid->next;
1021       if (!uid)
1022         break;
1023     }
1024
1025   switch (what)
1026     {
1027     case GPGME_ATTR_ALGO:
1028       return subkey ? (unsigned long) subkey->key_algo : 0;
1029
1030     case GPGME_ATTR_LEN:
1031       return subkey ? (unsigned long) subkey->key_len : 0;
1032
1033     case GPGME_ATTR_TYPE:
1034       return key->x509 ? 1 : 0;
1035
1036     case GPGME_ATTR_CREATED: 
1037       return (subkey && subkey->timestamp >= 0)
1038         ? (unsigned long) subkey->timestamp : 0;
1039
1040     case GPGME_ATTR_EXPIRE: 
1041       return (subkey && subkey->expires_at >= 0)
1042         ? (unsigned long) subkey->expires_at : 0;
1043
1044     case GPGME_ATTR_VALIDITY:
1045       return uid ? uid->validity : 0;
1046
1047     case GPGME_ATTR_OTRUST:
1048       return key->otrust;
1049
1050     case GPGME_ATTR_IS_SECRET:
1051       return !!key->secret;
1052
1053     case GPGME_ATTR_KEY_REVOKED:
1054       return subkey ? subkey->flags.revoked : 0;
1055
1056     case GPGME_ATTR_KEY_INVALID:
1057       return subkey ? subkey->flags.invalid : 0;
1058
1059     case GPGME_ATTR_KEY_EXPIRED:
1060       return subkey ? subkey->flags.expired : 0;
1061
1062     case GPGME_ATTR_KEY_DISABLED:
1063       return subkey ? subkey->flags.disabled : 0;
1064
1065     case GPGME_ATTR_UID_REVOKED:
1066       return uid ? uid->revoked : 0;
1067
1068     case GPGME_ATTR_UID_INVALID:
1069       return uid ? uid->invalid : 0;
1070
1071     case GPGME_ATTR_CAN_ENCRYPT:
1072       return key->gloflags.can_encrypt;
1073
1074     case GPGME_ATTR_CAN_SIGN:
1075       return key->gloflags.can_sign;
1076
1077     case GPGME_ATTR_CAN_CERTIFY:
1078       return key->gloflags.can_certify;
1079
1080     default:
1081       return 0;
1082     }
1083 }
1084
1085
1086 static struct certsig_s *
1087 get_certsig (GpgmeKey key, int uid_idx, int idx)
1088 {
1089   struct user_id_s *uid;
1090   struct certsig_s *certsig;
1091
1092   if (!key || uid_idx < 0 || idx < 0)
1093     return NULL;
1094
1095   uid = key->uids;
1096   while (uid && uid_idx > 0)
1097     {
1098       uid = uid->next;
1099       uid_idx--;
1100     }
1101   if (!uid)
1102     return NULL;
1103
1104   certsig = uid->certsigs;
1105   while (certsig && idx > 0)
1106     {
1107       certsig = certsig->next;
1108       idx--;
1109     }
1110   return certsig;
1111 }
1112
1113
1114 const char *
1115 gpgme_key_sig_get_string_attr (GpgmeKey key, int uid_idx, GpgmeAttr what,
1116                                const void *reserved, int idx)
1117 {
1118   struct certsig_s *certsig = get_certsig (key, uid_idx, idx);
1119
1120   if (!certsig || reserved)
1121     return NULL;
1122
1123   switch (what)
1124     {
1125     case GPGME_ATTR_KEYID:
1126       return certsig->keyid;
1127
1128     case GPGME_ATTR_ALGO:    
1129       return pkalgo_to_string (certsig->algo);
1130
1131     case GPGME_ATTR_USERID:  
1132       return certsig->name;
1133
1134     case GPGME_ATTR_NAME:   
1135       return certsig->name_part;
1136
1137     case GPGME_ATTR_EMAIL:
1138       return certsig->email_part;
1139
1140     case GPGME_ATTR_COMMENT:
1141       return certsig->comment_part;
1142    
1143     default:
1144       return NULL;
1145     }
1146 }
1147
1148
1149 unsigned long
1150 gpgme_key_sig_get_ulong_attr (GpgmeKey key, int uid_idx, GpgmeAttr what,
1151                               const void *reserved, int idx)
1152 {
1153   struct certsig_s *certsig = get_certsig (key, uid_idx, idx);
1154
1155   if (!certsig || reserved)
1156     return 0;
1157
1158   switch (what)
1159     {
1160     case GPGME_ATTR_ALGO:    
1161       return (unsigned long) certsig->algo;
1162
1163     case GPGME_ATTR_CREATED: 
1164       return certsig->timestamp < 0 ? 0L : (unsigned long) certsig->timestamp;
1165
1166     case GPGME_ATTR_EXPIRE: 
1167       return certsig->expires_at < 0 ? 0L : (unsigned long) certsig->expires_at;
1168
1169     case GPGME_ATTR_KEY_REVOKED:
1170       return certsig->flags.revoked;
1171
1172     case GPGME_ATTR_KEY_INVALID:
1173       return certsig->flags.invalid;
1174
1175     case GPGME_ATTR_KEY_EXPIRED:
1176       return certsig->flags.expired;
1177
1178     case GPGME_ATTR_SIG_CLASS:
1179       return certsig->sig_class;
1180
1181     case GPGME_ATTR_SIG_STATUS:
1182       return certsig->sig_stat;
1183
1184     default:
1185       return 0;
1186     }
1187 }
1188
1189
1190 /* Get the key with the fingerprint FPR from the key cache or from the
1191    crypto backend.  If FORCE_UPDATE is true, force a refresh of the
1192    key from the crypto backend and replace the key in the cache, if
1193    any.  If SECRET is true, get the secret key.  */
1194 GpgmeError
1195 gpgme_get_key (GpgmeCtx ctx, const char *fpr, GpgmeKey *r_key,
1196                int secret, int force_update)
1197 {
1198   GpgmeCtx listctx;
1199   GpgmeError err;
1200
1201   if (!ctx || !r_key)
1202     return GPGME_Invalid_Value;
1203   if (ctx->pending)
1204     return GPGME_Busy;
1205   
1206   if (strlen (fpr) < 16)        /* We have at least a key ID.  */
1207     return GPGME_Invalid_Key;
1208
1209   if (!force_update)
1210     {
1211       *r_key = _gpgme_key_cache_get (fpr);
1212       if (*r_key)
1213         {
1214           /* If the primary UID (if available) has no signatures, and
1215              we are in the signature listing keylist mode, then try to
1216              update the key below before returning.  */
1217           if (!((ctx->keylist_mode & GPGME_KEYLIST_MODE_SIGS)
1218                 && (*r_key)->uids && !(*r_key)->uids->certsigs))
1219             return 0;
1220         }
1221     }
1222
1223   /* We need our own context because we have to avoid the user's I/O
1224      callback handlers.  */
1225   /* Fixme: This can be optimized by keeping an internal context
1226      used for such key listings.  */
1227   err = gpgme_new (&listctx);
1228   if (err)
1229     return err;
1230   gpgme_set_protocol (listctx, gpgme_get_protocol (ctx));
1231   gpgme_set_keylist_mode (listctx, ctx->keylist_mode);
1232   err = gpgme_op_keylist_start (listctx, fpr, secret);
1233   if (!err)
1234     err = gpgme_op_keylist_next (listctx, r_key);
1235   gpgme_release (listctx);
1236   return err;
1237 }