2003-02-04 Marcus Brinkmann <marcus@g10code.de>
[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 /* Acquire a reference to KEY.  */
360 void
361 gpgme_key_ref (GpgmeKey key)
362 {
363   if (!key)
364     return;
365   LOCK (key_ref_lock);
366   key->ref_count++;
367   UNLOCK (key_ref_lock);
368 }
369
370 \f
371 static struct subkey_s *
372 add_subkey (GpgmeKey key, int secret)
373 {
374   struct subkey_s *k, *kk;
375
376   k = calloc (1, sizeof *k);
377   if (!k)
378     return NULL;
379
380   if (!(kk = key->keys.next))
381     key->keys.next = k;
382   else
383     {
384       while (kk->next)
385         kk = kk->next;
386       kk->next = k;
387     }
388   if (secret)
389     k->secret = 1;
390   return k;
391 }
392
393
394 struct subkey_s *
395 _gpgme_key_add_subkey (GpgmeKey key)
396 {
397   return add_subkey (key, 0);
398 }
399
400
401 struct subkey_s *
402 _gpgme_key_add_secret_subkey (GpgmeKey key)
403 {
404   return add_subkey (key, 1);
405 }
406
407 \f
408 static char *
409 set_user_id_part (char *tail, const char *buf, size_t len)
410 {
411   while (len && (buf[len - 1] == ' ' || buf[len - 1] == '\t')) 
412     len--;
413   for (; len; len--)
414     *tail++ = *buf++;
415   *tail++ = 0;
416   return tail;
417 }
418
419
420 static void
421 parse_user_id (const char *src, const char **name, const char **email,
422                     const char **comment, char *tail)
423 {
424   const char *start = NULL;
425   int in_name = 0;
426   int in_email = 0;
427   int in_comment = 0;
428
429   while (*src)
430     {
431       if (in_email)
432         {
433           if (*src == '<')
434             /* Not legal but anyway.  */
435             in_email++;
436           else if (*src == '>')
437             {
438               if (!--in_email && !*email)
439                 {
440                   *email = tail;
441                   tail = set_user_id_part (tail, start, src - start);
442                 }
443             }
444         }
445       else if (in_comment)
446         {
447           if (*src == '(')
448             in_comment++;
449           else if (*src == ')')
450             {
451               if (!--in_comment && !*comment)
452                 {
453                   *comment = tail;
454                   tail = set_user_id_part (tail, start, src - start);
455                 }
456             }
457         }
458       else if (*src == '<')
459         {
460           if (in_name)
461             {
462               if (!*name)
463                 {
464                   *name = tail;
465                   tail = set_user_id_part (tail, start, src - start);
466                 }
467               in_name = 0;
468             }
469           in_email = 1;
470           start = src + 1;
471         }
472       else if (*src == '(')
473         {
474           if (in_name)
475             {
476               if (!*name)
477                 {
478                   *name = tail;
479                   tail = set_user_id_part (tail, start, src - start);
480                 }
481               in_name = 0;
482             }
483           in_comment = 1;
484           start = src + 1;
485         }
486       else if (!in_name && *src != ' ' && *src != '\t')
487         {
488           in_name = 1;
489           start = src;
490         }    
491       src++;
492     }
493  
494   if (in_name)
495     {
496       if (!*name)
497         {
498           *name = tail;
499           tail = set_user_id_part (tail, start, src - start);
500         }
501     }
502  
503   /* Let unused parts point to an EOS.  */
504   tail--;
505   if (!*name)
506     *name = tail;
507   if (!*email)
508     *email = tail;
509   if (!*comment)
510     *comment = tail;
511 }
512
513
514 static void
515 parse_x509_user_id (const char *src, const char **name, const char **email,
516                     const char **comment, char *tail)
517 {
518   if (*src == '<' && src[strlen (src) - 1] == '>')
519     *email = src;
520   
521   /* Let unused parts point to an EOS.  */
522   tail--;
523   if (!*name)
524     *name = tail;
525   if (!*email)
526     *email = tail;
527   if (!*comment)
528     *comment = tail;
529 }
530
531 \f
532 struct certsig_s *
533 _gpgme_key_add_certsig (GpgmeKey key, char *src)
534 {
535   int src_len = src ? strlen (src) : 0;
536   struct user_id_s *uid;
537   struct certsig_s *certsig;
538
539   assert (key); /* XXX */
540
541   uid = key->last_uid;
542   assert (uid); /* XXX */
543
544   /* We can malloc a buffer of the same length, because the converted
545      string will never be larger. Actually we allocate it twice the
546      size, so that we are able to store the parsed stuff there too.  */
547   certsig = calloc (1, sizeof (*certsig) + 2 * src_len + 3);
548   if (!certsig)
549     return NULL;
550
551   if (src)
552     {
553       char *dst = certsig->name;
554       _gpgme_decode_c_string (src, &dst, src_len + 1);
555       dst += src_len + 1;
556       if (key->x509)
557         parse_x509_user_id (src, &certsig->name_part, &certsig->email_part,
558                             &certsig->comment_part, dst);
559       else
560         parse_user_id (src, &certsig->name_part, &certsig->email_part,
561                        &certsig->comment_part, dst);
562     }
563
564   if (!uid->certsigs)
565     uid->certsigs = certsig;
566   if (uid->last_certsig)
567     uid->last_certsig->next = certsig;
568   uid->last_certsig = certsig;
569
570   return certsig;
571 }
572
573 \f
574 /**
575  * gpgme_key_release:
576  * @key: Key Object or NULL
577  * 
578  * Release the key object. Note, that this function may not do an
579  * actual release if there are other shallow copies of the objects.
580  * You have to call this function for every newly created key object
581  * as well as for every gpgme_key_ref() done on the key object.
582  **/
583 void
584 gpgme_key_release (GpgmeKey key)
585 {
586   struct certsig_s *c, *c2;
587   struct user_id_s *u, *u2;
588   struct subkey_s *k, *k2;
589
590   if (!key)
591     return;
592
593   LOCK (key_ref_lock);
594   assert (key->ref_count);
595   if (--key->ref_count)
596     {
597       UNLOCK (key_ref_lock);
598       return;
599     }
600   UNLOCK (key_ref_lock);
601
602   free (key->keys.fingerprint);
603   for (k = key->keys.next; k; k = k2)
604     {
605       k2 = k->next;
606       free (k->fingerprint);
607       free (k);
608     }
609   for (u = key->uids; u; u = u2)
610     {
611       u2 = u->next;
612       for (c = u->certsigs; c; c = c2)
613         {
614           c2 = c->next;
615           free (c);
616         }
617       free (u);
618     }
619   free (key->issuer_serial);
620   free (key->issuer_name);
621   free (key->chain_id);
622   free (key);
623 }
624
625
626 /**
627  * gpgme_key_unref:
628  * @key: Key Object
629  * 
630  * This is an alias for gpgme_key_release().
631  **/
632 void
633 gpgme_key_unref (GpgmeKey key)
634 {
635   gpgme_key_release (key);
636 }
637
638 \f
639 /* Take a name from the --with-colon listing, remove certain escape
640    sequences sequences and put it into the list of UIDs.  */
641 GpgmeError
642 _gpgme_key_append_name (GpgmeKey key, const char *src)
643 {
644   struct user_id_s *uid;
645   char *dst;
646   int src_len = strlen (src);
647
648   assert (key);
649   /* We can malloc a buffer of the same length, because the converted
650      string will never be larger. Actually we allocate it twice the
651      size, so that we are able to store the parsed stuff there too.  */
652   uid = malloc (sizeof (*uid) + 2 * src_len + 3);
653   if (!uid)
654     return GPGME_Out_Of_Core;
655   memset (uid, 0, sizeof *uid);
656
657   dst = uid->name;
658   _gpgme_decode_c_string (src, &dst, src_len + 1);
659
660   dst += src_len + 1;
661   if (key->x509)
662     parse_x509_user_id (src, &uid->name_part, &uid->email_part,
663                         &uid->comment_part, dst);
664   else
665     parse_user_id (src, &uid->name_part, &uid->email_part,
666                    &uid->comment_part, dst);
667
668   if (!key->uids)
669     key->uids = uid;
670   if (key->last_uid)
671     key->last_uid->next = uid;
672   key->last_uid = uid;
673
674   return 0;
675 }
676
677
678 static void
679 add_otag (GpgmeData d, const char *tag)
680 {
681   _gpgme_data_append_string (d, "    <");
682   _gpgme_data_append_string (d, tag);
683   _gpgme_data_append_string (d, ">");
684 }
685
686
687 static void
688 add_ctag (GpgmeData d, const char *tag)
689 {
690   _gpgme_data_append_string (d, "</");
691   _gpgme_data_append_string (d, tag);
692   _gpgme_data_append_string (d, ">\n");
693 }
694
695
696 static void
697 add_tag_and_string (GpgmeData d, const char *tag, const char *string)
698 {
699   add_otag (d, tag);
700   _gpgme_data_append_string_for_xml (d, string);
701   add_ctag (d, tag); 
702 }
703
704
705 static void
706 add_tag_and_uint (GpgmeData d, const char *tag, unsigned int val)
707 {
708   char buf[30];
709   sprintf (buf, "%u", val);
710   add_tag_and_string (d, tag, buf);
711 }
712
713
714 static void
715 add_tag_and_time (GpgmeData d, const char *tag, time_t val)
716 {
717   char buf[30];
718
719   if (!val || val == (time_t) - 1)
720     return;
721   sprintf (buf, "%lu", (unsigned long) val);
722   add_tag_and_string (d, tag, buf);
723 }
724
725
726 static void
727 one_certsig_as_xml (GpgmeData data, struct certsig_s *certsig)
728 {
729   _gpgme_data_append_string (data, "    <signature>\n");
730   if (certsig->flags.invalid)
731     _gpgme_data_append_string (data, "      <invalid/>\n");
732   if (certsig->flags.revoked)
733     _gpgme_data_append_string (data, "      <revoked/>\n");
734   if (certsig->flags.expired)
735     _gpgme_data_append_string (data, "      <expired/>\n");
736   add_tag_and_string (data, "keyid", certsig->keyid);
737   add_tag_and_uint (data, "algo", certsig->algo);
738   add_tag_and_time (data, "created", certsig->timestamp);
739   add_tag_and_time (data, "expire", certsig->expires_at);
740   if (*certsig->name)
741     add_tag_and_string (data, "raw", certsig->name);
742   if (*certsig->name_part)
743     add_tag_and_string (data, "name", certsig->name_part);
744   if (*certsig->email_part)
745     add_tag_and_string (data, "email", certsig->email_part);
746   if (*certsig->comment_part)
747     add_tag_and_string (data, "comment", certsig->comment_part);
748   _gpgme_data_append_string (data, "    </signature>\n");
749 }
750
751
752 static void
753 one_uid_as_xml (GpgmeData data, struct user_id_s *uid)
754 {
755   struct certsig_s *certsig;
756
757   _gpgme_data_append_string (data, "  <userid>\n");
758   if (uid->invalid)
759     _gpgme_data_append_string (data, "    <invalid/>\n");
760   if (uid->revoked)
761     _gpgme_data_append_string (data, "    <revoked/>\n");
762   add_tag_and_string (data, "raw", uid->name);
763   if (*uid->name_part)
764     add_tag_and_string (data, "name", uid->name_part);
765   if (*uid->email_part)
766     add_tag_and_string (data, "email", uid->email_part);
767   if (*uid->comment_part)
768     add_tag_and_string (data, "comment", uid->comment_part);
769
770   /* Now the signatures.  */
771   for (certsig = uid->certsigs; certsig; certsig = certsig->next)
772     one_certsig_as_xml (data, certsig);
773   _gpgme_data_append_string (data, "  </userid>\n");
774 }
775
776
777 /**
778  * gpgme_key_get_as_xml:
779  * @key: Key object
780  * 
781  * Return the key object as an XML string.  The classer has to free
782  * that string.
783  * 
784  * Return value:  An XML string or NULL in case of a memory problem or
785  *                a NULL passed as @key
786  **/
787 char *
788 gpgme_key_get_as_xml (GpgmeKey key)
789 {
790   GpgmeData d;
791   struct user_id_s *u;
792   struct subkey_s *k;
793   
794   if (!key)
795     return NULL;
796   
797   if (gpgme_data_new (&d))
798     return NULL;
799   
800   _gpgme_data_append_string (d, "<GnupgKeyblock>\n"
801                              "  <mainkey>\n");
802   if (key->keys.secret)
803     _gpgme_data_append_string (d, "    <secret/>\n");
804   if (key->keys.flags.invalid)
805     _gpgme_data_append_string (d, "    <invalid/>\n");
806   if (key->keys.flags.revoked)
807     _gpgme_data_append_string (d, "    <revoked/>\n");
808   if (key->keys.flags.expired)
809     _gpgme_data_append_string (d, "    <expired/>\n");
810   if (key->keys.flags.disabled)
811     _gpgme_data_append_string (d, "    <disabled/>\n");
812   add_tag_and_string (d, "keyid", key->keys.keyid);
813   if (key->keys.fingerprint)
814     add_tag_and_string (d, "fpr", key->keys.fingerprint);
815   add_tag_and_uint (d, "algo", key->keys.key_algo);
816   add_tag_and_uint (d, "len", key->keys.key_len);
817   add_tag_and_time (d, "created", key->keys.timestamp);
818   add_tag_and_time (d, "expire", key->keys.expires_at);
819   add_tag_and_string (d, "otrust", otrust_to_string (key->otrust));
820   if (key->issuer_serial)
821     add_tag_and_string (d, "serial", key->issuer_serial);
822   if (key->issuer_name)
823     add_tag_and_string (d, "issuer", key->issuer_name);
824   if (key->chain_id)
825     add_tag_and_string (d, "chainid", key->chain_id);
826   _gpgme_data_append_string (d, "  </mainkey>\n");
827
828   /* Now the user IDs.  */
829   for (u = key->uids; u; u = u->next)
830     one_uid_as_xml (d,u);
831   
832   /* And now the subkeys.  */
833   for (k = key->keys.next; k; k = k->next)
834     {
835       _gpgme_data_append_string (d, "  <subkey>\n");
836       if (k->secret)
837         _gpgme_data_append_string (d, "    <secret/>\n");
838       if (k->flags.invalid)
839         _gpgme_data_append_string (d, "    <invalid/>\n");
840       if (k->flags.revoked)
841         _gpgme_data_append_string (d, "    <revoked/>\n");
842       if (k->flags.expired)
843         _gpgme_data_append_string (d, "    <expired/>\n");
844       if (k->flags.disabled)
845         _gpgme_data_append_string (d, "    <disabled/>\n");
846       add_tag_and_string (d, "keyid", k->keyid);
847       if (k->fingerprint)
848         add_tag_and_string (d, "fpr", k->fingerprint);
849       add_tag_and_uint (d, "algo", k->key_algo);
850       add_tag_and_uint (d, "len", k->key_len);
851       add_tag_and_time (d, "created", k->timestamp);
852       add_tag_and_time (d, "expire", k->expires_at);
853       _gpgme_data_append_string (d, "  </subkey>\n");
854     }
855   _gpgme_data_append_string (d, "</GnupgKeyblock>\n");
856   
857   return _gpgme_data_release_and_return_string (d);
858 }
859
860
861 static const char *
862 capabilities_to_string (struct subkey_s *k)
863 {
864   static const char *const strings[8] =
865     {
866       "",
867       "c",
868       "s",
869       "sc",
870       "e",
871       "ec",
872       "es",
873       "esc"
874     };
875   return strings[(!!k->flags.can_encrypt << 2)
876                  | (!!k->flags.can_sign << 1)
877                  | (!!k->flags.can_certify)];
878 }
879
880
881 /**
882  * gpgme_key_get_string_attr:
883  * @key: Key Object
884  * @what: Attribute specifier
885  * @reserved: Must be 0
886  * @idx: Index counter
887  * 
888  * Return a attribute as specified by @what and @idx.  Note that not
889  * all attributes can be returned as a string, in which case NULL is
890  * returned.  @idx is used to iterate through attributes which do have
891  * more than one instance (e.g. user IDs or sub keys).
892  * 
893  * Return value: NULL or an const string which is only valid as long
894  * as the key object itself is valid.
895  **/
896 const char *
897 gpgme_key_get_string_attr (GpgmeKey key, GpgmeAttr what,
898                            const void *reserved, int idx)
899 {
900   struct subkey_s *subkey;
901   struct user_id_s *uid;
902   int i;
903
904   if (!key || reserved || idx < 0)
905     return NULL;
906
907   /* Select IDXth subkey.  */
908   subkey = &key->keys;
909   for (i = 0; i < idx; i++)
910     {
911       subkey = subkey->next;
912       if (!subkey)
913         break;
914     }
915
916   /* Select the IDXth user ID.  */
917   uid = key->uids;
918   for (i = 0; i < idx; i++)
919     {
920       uid = uid->next;
921       if (!uid)
922         break;
923     }
924
925   switch (what)
926     {
927     case GPGME_ATTR_KEYID:
928       return subkey ? subkey->keyid : NULL;
929
930     case GPGME_ATTR_FPR:
931       return subkey ? subkey->fingerprint : NULL;
932
933     case GPGME_ATTR_ALGO:    
934       return subkey ? pkalgo_to_string (subkey->key_algo) : NULL;
935
936     case GPGME_ATTR_TYPE:
937       return key->x509 ? "X.509" : "PGP";
938
939     case GPGME_ATTR_OTRUST:
940       return otrust_to_string (key->otrust);
941
942     case GPGME_ATTR_USERID:  
943       return uid ? uid->name : NULL;
944
945     case GPGME_ATTR_NAME:   
946       return uid ? uid->name_part : NULL;
947
948     case GPGME_ATTR_EMAIL:
949       return uid ? uid->email_part : NULL;
950
951     case GPGME_ATTR_COMMENT:
952       return uid ? uid->comment_part : NULL;
953
954     case GPGME_ATTR_VALIDITY:
955       return validity_to_string (key->otrust);
956
957     case GPGME_ATTR_KEY_CAPS:    
958       return subkey ? capabilities_to_string (subkey) : NULL;
959
960     case GPGME_ATTR_SERIAL:
961       return key->issuer_serial;
962
963     case GPGME_ATTR_ISSUER:
964       return idx ? NULL : key->issuer_name;
965
966     case GPGME_ATTR_CHAINID:
967       return  key->chain_id;
968
969     default:
970       return NULL;
971     }
972 }
973
974
975 /**
976  * gpgme_key_get_ulong_attr:
977  * @key: 
978  * @what: 
979  * @reserved: 
980  * @idx: 
981  * 
982  * Return a attribute as specified by @what and @idx.  Note that not
983  * all attributes can be returned as an integer, in which case 0 is
984  * returned.  @idx is used to iterate through attributes which do have
985  * more than one instance (e.g. user IDs or sub keys).
986  *
987  * See gpgme.h for a list of attributes.
988  * 
989  * Return value: 0 or the requested value.
990  **/
991 unsigned long
992 gpgme_key_get_ulong_attr (GpgmeKey key, GpgmeAttr what,
993                           const void *reserved, int idx)
994 {
995   struct subkey_s *subkey;
996   struct user_id_s *uid;
997   int i;
998
999   if (!key || reserved || idx < 0)
1000     return 0;
1001
1002   /* Select IDXth subkey.  */
1003   subkey = &key->keys;
1004   for (i = 0; i < idx; i++)
1005     {
1006       subkey = subkey->next;
1007       if (!subkey)
1008         break;
1009     }
1010
1011   /* Select the IDXth user ID.  */
1012   uid = key->uids;
1013   for (i = 0; i < idx; i++)
1014     {
1015       uid = uid->next;
1016       if (!uid)
1017         break;
1018     }
1019
1020   switch (what)
1021     {
1022     case GPGME_ATTR_ALGO:
1023       return subkey ? (unsigned long) subkey->key_algo : 0;
1024
1025     case GPGME_ATTR_LEN:
1026       return subkey ? (unsigned long) subkey->key_len : 0;
1027
1028     case GPGME_ATTR_TYPE:
1029       return key->x509 ? 1 : 0;
1030
1031     case GPGME_ATTR_CREATED: 
1032       return (subkey && subkey->timestamp >= 0)
1033         ? (unsigned long) subkey->timestamp : 0;
1034
1035     case GPGME_ATTR_EXPIRE: 
1036       return (subkey && subkey->expires_at >= 0)
1037         ? (unsigned long) subkey->expires_at : 0;
1038
1039     case GPGME_ATTR_VALIDITY:
1040       return uid ? uid->validity : 0;
1041
1042     case GPGME_ATTR_OTRUST:
1043       return key->otrust;
1044
1045     case GPGME_ATTR_IS_SECRET:
1046       return !!key->secret;
1047
1048     case GPGME_ATTR_KEY_REVOKED:
1049       return subkey ? subkey->flags.revoked : 0;
1050
1051     case GPGME_ATTR_KEY_INVALID:
1052       return subkey ? subkey->flags.invalid : 0;
1053
1054     case GPGME_ATTR_KEY_EXPIRED:
1055       return subkey ? subkey->flags.expired : 0;
1056
1057     case GPGME_ATTR_KEY_DISABLED:
1058       return subkey ? subkey->flags.disabled : 0;
1059
1060     case GPGME_ATTR_UID_REVOKED:
1061       return uid ? uid->revoked : 0;
1062
1063     case GPGME_ATTR_UID_INVALID:
1064       return uid ? uid->invalid : 0;
1065
1066     case GPGME_ATTR_CAN_ENCRYPT:
1067       return key->gloflags.can_encrypt;
1068
1069     case GPGME_ATTR_CAN_SIGN:
1070       return key->gloflags.can_sign;
1071
1072     case GPGME_ATTR_CAN_CERTIFY:
1073       return key->gloflags.can_certify;
1074
1075     default:
1076       return 0;
1077     }
1078 }
1079
1080
1081 static struct certsig_s *
1082 get_certsig (GpgmeKey key, int uid_idx, int idx)
1083 {
1084   struct user_id_s *uid;
1085   struct certsig_s *certsig;
1086
1087   if (!key || uid_idx < 0 || idx < 0)
1088     return NULL;
1089
1090   uid = key->uids;
1091   while (uid && uid_idx > 0)
1092     {
1093       uid = uid->next;
1094       uid_idx--;
1095     }
1096   if (!uid)
1097     return NULL;
1098
1099   certsig = uid->certsigs;
1100   while (certsig && idx > 0)
1101     {
1102       certsig = certsig->next;
1103       idx--;
1104     }
1105   return certsig;
1106 }
1107
1108
1109 const char *
1110 gpgme_key_sig_get_string_attr (GpgmeKey key, int uid_idx, GpgmeAttr what,
1111                                const void *reserved, int idx)
1112 {
1113   struct certsig_s *certsig = get_certsig (key, uid_idx, idx);
1114
1115   if (!certsig || reserved)
1116     return NULL;
1117
1118   switch (what)
1119     {
1120     case GPGME_ATTR_KEYID:
1121       return certsig->keyid;
1122
1123     case GPGME_ATTR_ALGO:    
1124       return pkalgo_to_string (certsig->algo);
1125
1126     case GPGME_ATTR_USERID:  
1127       return certsig->name;
1128
1129     case GPGME_ATTR_NAME:   
1130       return certsig->name_part;
1131
1132     case GPGME_ATTR_EMAIL:
1133       return certsig->email_part;
1134
1135     case GPGME_ATTR_COMMENT:
1136       return certsig->comment_part;
1137    
1138     default:
1139       return NULL;
1140     }
1141 }
1142
1143
1144 unsigned long
1145 gpgme_key_sig_get_ulong_attr (GpgmeKey key, int uid_idx, GpgmeAttr what,
1146                               const void *reserved, int idx)
1147 {
1148   struct certsig_s *certsig = get_certsig (key, uid_idx, idx);
1149
1150   if (!certsig || reserved)
1151     return 0;
1152
1153   switch (what)
1154     {
1155     case GPGME_ATTR_ALGO:    
1156       return (unsigned long) certsig->algo;
1157
1158     case GPGME_ATTR_CREATED: 
1159       return certsig->timestamp < 0 ? 0L : (unsigned long) certsig->timestamp;
1160
1161     case GPGME_ATTR_EXPIRE: 
1162       return certsig->expires_at < 0 ? 0L : (unsigned long) certsig->expires_at;
1163
1164     case GPGME_ATTR_KEY_REVOKED:
1165       return certsig->flags.revoked;
1166
1167     case GPGME_ATTR_KEY_INVALID:
1168       return certsig->flags.invalid;
1169
1170     case GPGME_ATTR_KEY_EXPIRED:
1171       return certsig->flags.expired;
1172
1173     case GPGME_ATTR_SIG_CLASS:
1174       return certsig->sig_class;
1175
1176     case GPGME_ATTR_SIG_STATUS:
1177       return certsig->sig_stat;
1178
1179     default:
1180       return 0;
1181     }
1182 }
1183
1184
1185 /* Get the key with the fingerprint FPR from the key cache or from the
1186    crypto backend.  If FORCE_UPDATE is true, force a refresh of the
1187    key from the crypto backend and replace the key in the cache, if
1188    any.  If SECRET is true, get the secret key.  */
1189 GpgmeError
1190 gpgme_get_key (GpgmeCtx ctx, const char *fpr, GpgmeKey *r_key,
1191                int secret, int force_update)
1192 {
1193   GpgmeCtx listctx;
1194   GpgmeError err;
1195
1196   if (!ctx || !r_key)
1197     return GPGME_Invalid_Value;
1198   if (ctx->pending)
1199     return GPGME_Busy;
1200   
1201   if (strlen (fpr) < 16)        /* We have at least a key ID.  */
1202     return GPGME_Invalid_Key;
1203
1204   if (!force_update)
1205     {
1206       *r_key = _gpgme_key_cache_get (fpr);
1207       if (*r_key)
1208         {
1209           /* If the primary UID (if available) has no signatures, and
1210              we are in the signature listing keylist mode, then try to
1211              update the key below before returning.  */
1212           if (!((ctx->keylist_mode & GPGME_KEYLIST_MODE_SIGS)
1213                 && (*r_key)->uids && !(*r_key)->uids->certsigs))
1214             return 0;
1215         }
1216     }
1217
1218   /* We need our own context because we have to avoid the user's I/O
1219      callback handlers.  */
1220   /* Fixme: This can be optimized by keeping an internal context
1221      used for such key listings.  */
1222   err = gpgme_new (&listctx);
1223   if (err)
1224     return err;
1225   gpgme_set_protocol (listctx, gpgme_get_protocol (ctx));
1226   gpgme_set_keylist_mode (listctx, ctx->keylist_mode);
1227   err = gpgme_op_keylist_start (listctx, fpr, secret);
1228   if (!err)
1229     err = gpgme_op_keylist_next (listctx, r_key);
1230   gpgme_release (listctx);
1231   return err;
1232 }