2004-06-23 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 <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <errno.h>
28
29 #include "util.h"
30 #include "ops.h"
31 #include "sema.h"
32
33 \f
34 /* Protects all reference counters in keys.  All other accesses to a
35    key are read only.  */
36 DEFINE_STATIC_LOCK (key_ref_lock);
37
38
39 /* Create a new key.  */
40 gpgme_error_t
41 _gpgme_key_new (gpgme_key_t *r_key)
42 {
43   gpgme_key_t key;
44
45   key = calloc (1, sizeof *key);
46   if (!key)
47     return gpg_error_from_errno (errno);
48   key->_refs = 1;
49
50   *r_key = key;
51   return 0;
52 }
53
54
55 gpgme_error_t
56 _gpgme_key_add_subkey (gpgme_key_t key, gpgme_subkey_t *r_subkey)
57 {
58   gpgme_subkey_t subkey;
59
60   subkey = calloc (1, sizeof *subkey);
61   if (!subkey)
62     return gpg_error_from_errno (errno);
63   subkey->keyid = subkey->_keyid;
64   subkey->_keyid[16] = '\0';
65
66   if (!key->subkeys)
67     key->subkeys = subkey;
68   if (key->_last_subkey)
69     key->_last_subkey->next = subkey;
70   key->_last_subkey = subkey;
71
72   *r_subkey = subkey;
73   return 0;
74 }
75
76
77 static char *
78 set_user_id_part (char *tail, const char *buf, size_t len)
79 {
80   while (len && (buf[len - 1] == ' ' || buf[len - 1] == '\t')) 
81     len--;
82   for (; len; len--)
83     *tail++ = *buf++;
84   *tail++ = 0;
85   return tail;
86 }
87
88
89 static void
90 parse_user_id (char *src, char **name, char **email,
91                char **comment, char *tail)
92 {
93   const char *start = NULL;
94   int in_name = 0;
95   int in_email = 0;
96   int in_comment = 0;
97
98   while (*src)
99     {
100       if (in_email)
101         {
102           if (*src == '<')
103             /* Not legal but anyway.  */
104             in_email++;
105           else if (*src == '>')
106             {
107               if (!--in_email && !*email)
108                 {
109                   *email = tail;
110                   tail = set_user_id_part (tail, start, src - start);
111                 }
112             }
113         }
114       else if (in_comment)
115         {
116           if (*src == '(')
117             in_comment++;
118           else if (*src == ')')
119             {
120               if (!--in_comment && !*comment)
121                 {
122                   *comment = tail;
123                   tail = set_user_id_part (tail, start, src - start);
124                 }
125             }
126         }
127       else if (*src == '<')
128         {
129           if (in_name)
130             {
131               if (!*name)
132                 {
133                   *name = tail;
134                   tail = set_user_id_part (tail, start, src - start);
135                 }
136               in_name = 0;
137             }
138           in_email = 1;
139           start = src + 1;
140         }
141       else if (*src == '(')
142         {
143           if (in_name)
144             {
145               if (!*name)
146                 {
147                   *name = tail;
148                   tail = set_user_id_part (tail, start, src - start);
149                 }
150               in_name = 0;
151             }
152           in_comment = 1;
153           start = src + 1;
154         }
155       else if (!in_name && *src != ' ' && *src != '\t')
156         {
157           in_name = 1;
158           start = src;
159         }    
160       src++;
161     }
162  
163   if (in_name)
164     {
165       if (!*name)
166         {
167           *name = tail;
168           tail = set_user_id_part (tail, start, src - start);
169         }
170     }
171  
172   /* Let unused parts point to an EOS.  */
173   tail--;
174   if (!*name)
175     *name = tail;
176   if (!*email)
177     *email = tail;
178   if (!*comment)
179     *comment = tail;
180 }
181
182
183 static void
184 parse_x509_user_id (char *src, char **name, char **email,
185                     char **comment, char *tail)
186 {
187   if (*src == '<' && src[strlen (src) - 1] == '>')
188     *email = src;
189   
190   /* Let unused parts point to an EOS.  */
191   tail--;
192   if (!*name)
193     *name = tail;
194   if (!*email)
195     *email = tail;
196   if (!*comment)
197     *comment = tail;
198 }
199
200
201 /* Take a name from the --with-colon listing, remove certain escape
202    sequences sequences and put it into the list of UIDs.  */
203 gpgme_error_t
204 _gpgme_key_append_name (gpgme_key_t key, char *src)
205 {
206   gpgme_user_id_t uid;
207   char *dst;
208   int src_len = strlen (src);
209
210   assert (key);
211   /* We can malloc a buffer of the same length, because the converted
212      string will never be larger. Actually we allocate it twice the
213      size, so that we are able to store the parsed stuff there too.  */
214   uid = malloc (sizeof (*uid) + 2 * src_len + 3);
215   if (!uid)
216     return gpg_error_from_errno (errno);
217   memset (uid, 0, sizeof *uid);
218
219   uid->uid = ((char *) uid) + sizeof (*uid);
220   dst = uid->uid;
221   _gpgme_decode_c_string (src, &dst, src_len + 1);
222
223   dst += src_len + 1;
224   if (key->protocol == GPGME_PROTOCOL_CMS)
225     parse_x509_user_id (uid->uid, &uid->name, &uid->email,
226                         &uid->comment, dst);
227   else
228     parse_user_id (uid->uid, &uid->name, &uid->email,
229                    &uid->comment, dst);
230
231   if (!key->uids)
232     key->uids = uid;
233   if (key->_last_uid)
234     key->_last_uid->next = uid;
235   key->_last_uid = uid;
236
237   return 0;
238 }
239
240
241 gpgme_key_sig_t
242 _gpgme_key_add_sig (gpgme_key_t key, char *src)
243 {
244   int src_len = src ? strlen (src) : 0;
245   gpgme_user_id_t uid;
246   gpgme_key_sig_t sig;
247
248   assert (key); /* XXX */
249
250   uid = key->_last_uid;
251   assert (uid); /* XXX */
252
253   /* We can malloc a buffer of the same length, because the converted
254      string will never be larger. Actually we allocate it twice the
255      size, so that we are able to store the parsed stuff there too.  */
256   sig = calloc (1, sizeof (*sig) + 2 * src_len + 3);
257   if (!sig)
258     return NULL;
259   sig->keyid = sig->_keyid;
260   sig->_keyid[16] = '\0';
261   sig->uid = ((char *) sig) + sizeof (*sig);
262
263   if (src)
264     {
265       char *dst = sig->uid;
266       _gpgme_decode_c_string (src, &dst, src_len + 1);
267       dst += src_len + 1;
268       if (key->protocol == GPGME_PROTOCOL_CMS)
269         parse_x509_user_id (sig->uid, &sig->name, &sig->email,
270                             &sig->comment, dst);
271       else
272         parse_user_id (sig->uid, &sig->name, &sig->email,
273                        &sig->comment, dst);
274     }
275
276   if (!uid->signatures)
277     uid->signatures = sig;
278   if (uid->_last_keysig)
279     uid->_last_keysig->next = sig;
280   uid->_last_keysig = sig;
281
282   return sig;
283 }
284
285 \f
286 /* Acquire a reference to KEY.  */
287 void
288 gpgme_key_ref (gpgme_key_t key)
289 {
290   LOCK (key_ref_lock);
291   key->_refs++;
292   UNLOCK (key_ref_lock);
293 }
294
295
296 /* gpgme_key_unref releases the key object.  Note, that this function
297    may not do an actual release if there are other shallow copies of
298    the objects.  You have to call this function for every newly
299    created key object as well as for every gpgme_key_ref() done on the
300    key object.  */
301 void
302 gpgme_key_unref (gpgme_key_t key)
303 {
304   gpgme_user_id_t uid;
305   gpgme_subkey_t subkey;
306
307   if (!key)
308     return;
309
310   LOCK (key_ref_lock);
311   assert (key->_refs > 0);
312   if (--key->_refs)
313     {
314       UNLOCK (key_ref_lock);
315       return;
316     }
317   UNLOCK (key_ref_lock);
318
319   subkey = key->subkeys;
320   while (subkey)
321     {
322       gpgme_subkey_t next = subkey->next;
323       if (subkey->fpr)
324         free (subkey->fpr);
325       free (subkey);
326       subkey = next;
327     }
328
329   uid = key->uids;
330   while (uid)
331     {
332       gpgme_user_id_t next_uid = uid->next;
333       gpgme_key_sig_t keysig = uid->signatures;
334
335       while (keysig)
336         {
337           gpgme_key_sig_t next = keysig->next;
338           free (keysig);
339           keysig = next;
340         }
341       free (uid);
342       uid = next_uid;
343     }
344   
345   if (key->issuer_serial)
346     free (key->issuer_serial);
347   if (key->issuer_name)
348     free (key->issuer_name);
349
350   if (key->chain_id)
351     free (key->chain_id);
352
353   free (key);
354 }
355
356 \f
357 /* Compatibility interfaces.  */
358
359 void
360 gpgme_key_release (gpgme_key_t key)
361 {
362   gpgme_key_unref (key);
363 }
364
365
366 static const char *
367 otrust_to_string (int otrust)
368 {
369   switch (otrust)
370     {
371     case GPGME_VALIDITY_NEVER:
372       return "n";
373
374     case GPGME_VALIDITY_MARGINAL:
375       return "m";
376
377     case GPGME_VALIDITY_FULL:
378       return "f";
379
380     case GPGME_VALIDITY_ULTIMATE:
381       return "u";
382
383     default:
384       return "?";
385     }
386 }
387
388
389 static const char *
390 validity_to_string (int validity)
391 {
392   switch (validity)
393     {
394     case GPGME_VALIDITY_UNDEFINED:
395       return "q";
396
397     case GPGME_VALIDITY_NEVER:
398       return "n";
399
400     case GPGME_VALIDITY_MARGINAL:
401       return "m";
402
403     case GPGME_VALIDITY_FULL:
404       return "f";
405
406     case GPGME_VALIDITY_ULTIMATE:
407       return "u";
408
409     case GPGME_VALIDITY_UNKNOWN:
410     default:
411       return "?";
412     }
413 }
414
415
416 static const char *
417 capabilities_to_string (gpgme_subkey_t subkey)
418 {
419   static const char *const strings[8] =
420     {
421       "",
422       "c",
423       "s",
424       "sc",
425       "e",
426       "ec",
427       "es",
428       "esc"
429     };
430   return strings[(!!subkey->can_encrypt << 2)
431                  | (!!subkey->can_sign << 1)
432                  | (!!subkey->can_certify)];
433 }
434
435
436 /* Return the value of the attribute WHAT of ITEM, which has to be
437    representable by a string.  */
438 const char *
439 gpgme_key_get_string_attr (gpgme_key_t key, _gpgme_attr_t what,
440                            const void *reserved, int idx)
441 {
442   gpgme_subkey_t subkey;
443   gpgme_user_id_t uid;
444   int i;
445
446   if (!key || reserved || idx < 0)
447     return NULL;
448
449   /* Select IDXth subkey.  */
450   subkey = key->subkeys;
451   for (i = 0; i < idx; i++)
452     {
453       subkey = subkey->next;
454       if (!subkey)
455         break;
456     }
457
458   /* Select the IDXth user ID.  */
459   uid = key->uids;
460   for (i = 0; i < idx; i++)
461     {
462       uid = uid->next;
463       if (!uid)
464         break;
465     }
466
467   switch (what)
468     {
469     case GPGME_ATTR_KEYID:
470       return subkey ? subkey->keyid : NULL;
471
472     case GPGME_ATTR_FPR:
473       return subkey ? subkey->fpr : NULL;
474
475     case GPGME_ATTR_ALGO:    
476       return subkey ? gpgme_pubkey_algo_name (subkey->pubkey_algo) : NULL;
477
478     case GPGME_ATTR_TYPE:
479       return key->protocol == GPGME_PROTOCOL_CMS ? "X.509" : "PGP";
480
481     case GPGME_ATTR_OTRUST:
482       return otrust_to_string (key->owner_trust);
483
484     case GPGME_ATTR_USERID:  
485       return uid ? uid->uid : NULL;
486
487     case GPGME_ATTR_NAME:   
488       return uid ? uid->name : NULL;
489
490     case GPGME_ATTR_EMAIL:
491       return uid ? uid->email : NULL;
492
493     case GPGME_ATTR_COMMENT:
494       return uid ? uid->comment : NULL;
495
496     case GPGME_ATTR_VALIDITY:
497       return uid ? validity_to_string (uid->validity) : NULL;
498
499     case GPGME_ATTR_KEY_CAPS:    
500       return subkey ? capabilities_to_string (subkey) : NULL;
501
502     case GPGME_ATTR_SERIAL:
503       return key->issuer_serial;
504
505     case GPGME_ATTR_ISSUER:
506       return idx ? NULL : key->issuer_name;
507
508     case GPGME_ATTR_CHAINID:
509       return key->chain_id;
510
511     default:
512       return NULL;
513     }
514 }
515
516
517 unsigned long
518 gpgme_key_get_ulong_attr (gpgme_key_t key, _gpgme_attr_t what,
519                           const void *reserved, int idx)
520 {
521   gpgme_subkey_t subkey;
522   gpgme_user_id_t uid;
523   int i;
524
525   if (!key || reserved || idx < 0)
526     return 0;
527
528   /* Select IDXth subkey.  */
529   subkey = key->subkeys;
530   for (i = 0; i < idx; i++)
531     {
532       subkey = subkey->next;
533       if (!subkey)
534         break;
535     }
536
537   /* Select the IDXth user ID.  */
538   uid = key->uids;
539   for (i = 0; i < idx; i++)
540     {
541       uid = uid->next;
542       if (!uid)
543         break;
544     }
545
546   switch (what)
547     {
548     case GPGME_ATTR_ALGO:
549       return subkey ? (unsigned long) subkey->pubkey_algo : 0;
550
551     case GPGME_ATTR_LEN:
552       return subkey ? (unsigned long) subkey->length : 0;
553
554     case GPGME_ATTR_TYPE:
555       return key->protocol == GPGME_PROTOCOL_CMS ? 1 : 0;
556
557     case GPGME_ATTR_CREATED:
558       return (subkey && subkey->timestamp >= 0)
559         ? (unsigned long) subkey->timestamp : 0;
560
561     case GPGME_ATTR_EXPIRE: 
562       return (subkey && subkey->expires >= 0)
563         ? (unsigned long) subkey->expires : 0;
564
565     case GPGME_ATTR_VALIDITY:
566       return uid ? uid->validity : 0;
567
568     case GPGME_ATTR_OTRUST:
569       return key->owner_trust;
570
571     case GPGME_ATTR_IS_SECRET:
572       return !!key->secret;
573
574     case GPGME_ATTR_KEY_REVOKED:
575       return subkey ? subkey->revoked : 0;
576
577     case GPGME_ATTR_KEY_INVALID:
578       return subkey ? subkey->invalid : 0;
579
580     case GPGME_ATTR_KEY_EXPIRED:
581       return subkey ? subkey->expired : 0;
582
583     case GPGME_ATTR_KEY_DISABLED:
584       return subkey ? subkey->disabled : 0;
585
586     case GPGME_ATTR_UID_REVOKED:
587       return uid ? uid->revoked : 0;
588
589     case GPGME_ATTR_UID_INVALID:
590       return uid ? uid->invalid : 0;
591
592     case GPGME_ATTR_CAN_ENCRYPT:
593       return key->can_encrypt;
594
595     case GPGME_ATTR_CAN_SIGN:
596       return key->can_sign;
597
598     case GPGME_ATTR_CAN_CERTIFY:
599       return key->can_certify;
600
601     default:
602       return 0;
603     }
604 }
605
606
607 static gpgme_key_sig_t
608 get_keysig (gpgme_key_t key, int uid_idx, int idx)
609 {
610   gpgme_user_id_t uid;
611   gpgme_key_sig_t sig;
612
613   if (!key || uid_idx < 0 || idx < 0)
614     return NULL;
615
616   uid = key->uids;
617   while (uid && uid_idx > 0)
618     {
619       uid = uid->next;
620       uid_idx--;
621     }
622   if (!uid)
623     return NULL;
624
625   sig = uid->signatures;
626   while (sig && idx > 0)
627     {
628       sig = sig->next;
629       idx--;
630     }
631   return sig;
632 }
633
634
635 const char *
636 gpgme_key_sig_get_string_attr (gpgme_key_t key, int uid_idx,
637                                _gpgme_attr_t what,
638                                const void *reserved, int idx)
639 {
640   gpgme_key_sig_t certsig = get_keysig (key, uid_idx, idx);
641
642   if (!certsig || reserved)
643     return NULL;
644
645   switch (what)
646     {
647     case GPGME_ATTR_KEYID:
648       return certsig->keyid;
649
650     case GPGME_ATTR_ALGO:    
651       return gpgme_pubkey_algo_name (certsig->pubkey_algo);
652
653     case GPGME_ATTR_USERID:
654       return certsig->uid;
655
656     case GPGME_ATTR_NAME:   
657       return certsig->name;
658
659     case GPGME_ATTR_EMAIL:
660       return certsig->email;
661
662     case GPGME_ATTR_COMMENT:
663       return certsig->comment;
664    
665     default:
666       return NULL;
667     }
668 }
669
670
671 unsigned long
672 gpgme_key_sig_get_ulong_attr (gpgme_key_t key, int uid_idx, _gpgme_attr_t what,
673                               const void *reserved, int idx)
674 {
675   gpgme_key_sig_t certsig = get_keysig (key, uid_idx, idx);
676
677   if (!certsig || reserved)
678     return 0;
679
680   switch (what)
681     {
682     case GPGME_ATTR_ALGO:    
683       return (unsigned long) certsig->pubkey_algo;
684
685     case GPGME_ATTR_CREATED: 
686       return certsig->timestamp < 0 ? 0L : (unsigned long) certsig->timestamp;
687
688     case GPGME_ATTR_EXPIRE: 
689       return certsig->expires < 0 ? 0L : (unsigned long) certsig->expires;
690
691     case GPGME_ATTR_KEY_REVOKED:
692       return certsig->revoked;
693
694     case GPGME_ATTR_KEY_INVALID:
695       return certsig->invalid;
696
697     case GPGME_ATTR_KEY_EXPIRED:
698       return certsig->expired;
699
700     case GPGME_ATTR_SIG_CLASS:
701       return certsig->sig_class;
702
703     case GPGME_ATTR_SIG_STATUS:
704       return certsig->status;
705
706     default:
707       return 0;
708     }
709 }