2003-05-18 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
28 #include "util.h"
29 #include "ops.h"
30 #include "sema.h"
31
32 \f
33 /* Protects all reference counters in keys.  All other accesses to a
34    key are either read only or happen before the key is entered into
35    the cache.  */
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 GPGME_Out_Of_Core;
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 GPGME_Out_Of_Core;
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 GPGME_Out_Of_Core;
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   LOCK (key_ref_lock);
308   assert (key->_refs > 0);
309   if (--key->_refs)
310     {
311       UNLOCK (key_ref_lock);
312       return;
313     }
314   UNLOCK (key_ref_lock);
315
316   subkey = key->subkeys;
317   while (subkey)
318     {
319       gpgme_subkey_t next = subkey->next;
320       if (subkey->fpr)
321         free (subkey->fpr);
322       free (subkey);
323       subkey = next;
324     }
325
326   uid = key->uids;
327   while (uid)
328     {
329       gpgme_user_id_t next_uid = uid->next;
330       gpgme_key_sig_t keysig = uid->signatures;
331
332       while (keysig)
333         {
334           gpgme_key_sig_t next = keysig->next;
335           free (keysig);
336           keysig = next;
337         }
338       free (uid);
339       uid = next_uid;
340     }
341   
342   if (key->issuer_serial)
343     free (key->issuer_serial);
344   if (key->issuer_name)
345     free (key->issuer_name);
346
347   if (key->chain_id)
348     free (key->chain_id);
349
350   free (key);
351 }
352
353 \f
354 /* Compatibility interfaces.  */
355
356 void
357 gpgme_key_release (gpgme_key_t key)
358 {
359   gpgme_key_unref (key);
360 }
361
362
363 static const char *
364 otrust_to_string (int otrust)
365 {
366   switch (otrust)
367     {
368     case GPGME_VALIDITY_NEVER:
369       return "n";
370
371     case GPGME_VALIDITY_MARGINAL:
372       return "m";
373
374     case GPGME_VALIDITY_FULL:
375       return "f";
376
377     case GPGME_VALIDITY_ULTIMATE:
378       return "u";
379
380     default:
381       return "?";
382     }
383 }
384
385
386 static const char *
387 validity_to_string (int validity)
388 {
389   switch (validity)
390     {
391     case GPGME_VALIDITY_UNDEFINED:
392       return "q";
393
394     case GPGME_VALIDITY_NEVER:
395       return "n";
396
397     case GPGME_VALIDITY_MARGINAL:
398       return "m";
399
400     case GPGME_VALIDITY_FULL:
401       return "f";
402
403     case GPGME_VALIDITY_ULTIMATE:
404       return "u";
405
406     case GPGME_VALIDITY_UNKNOWN:
407     default:
408       return "?";
409     }
410 }
411
412
413 static const char *
414 capabilities_to_string (gpgme_subkey_t subkey)
415 {
416   static const char *const strings[8] =
417     {
418       "",
419       "c",
420       "s",
421       "sc",
422       "e",
423       "ec",
424       "es",
425       "esc"
426     };
427   return strings[(!!subkey->can_encrypt << 2)
428                  | (!!subkey->can_sign << 1)
429                  | (!!subkey->can_certify)];
430 }
431
432
433 /* Return the value of the attribute WHAT of ITEM, which has to be
434    representable by a string.  */
435 const char *
436 gpgme_key_get_string_attr (gpgme_key_t key, _gpgme_attr_t what,
437                            const void *reserved, int idx)
438 {
439   gpgme_subkey_t subkey;
440   gpgme_user_id_t uid;
441   int i;
442
443   if (!key || reserved || idx < 0)
444     return NULL;
445
446   /* Select IDXth subkey.  */
447   subkey = key->subkeys;
448   for (i = 0; i < idx; i++)
449     {
450       subkey = subkey->next;
451       if (!subkey)
452         break;
453     }
454
455   /* Select the IDXth user ID.  */
456   uid = key->uids;
457   for (i = 0; i < idx; i++)
458     {
459       uid = uid->next;
460       if (!uid)
461         break;
462     }
463
464   switch (what)
465     {
466     case GPGME_ATTR_KEYID:
467       return subkey ? subkey->keyid : NULL;
468
469     case GPGME_ATTR_FPR:
470       return subkey ? subkey->fpr : NULL;
471
472     case GPGME_ATTR_ALGO:    
473       return subkey ? gpgme_pubkey_algo_name (subkey->pubkey_algo) : NULL;
474
475     case GPGME_ATTR_TYPE:
476       return key->protocol == GPGME_PROTOCOL_CMS ? "X.509" : "PGP";
477
478     case GPGME_ATTR_OTRUST:
479       return otrust_to_string (key->owner_trust);
480
481     case GPGME_ATTR_USERID:  
482       return uid ? uid->uid : NULL;
483
484     case GPGME_ATTR_NAME:   
485       return uid ? uid->name : NULL;
486
487     case GPGME_ATTR_EMAIL:
488       return uid ? uid->email : NULL;
489
490     case GPGME_ATTR_COMMENT:
491       return uid ? uid->comment : NULL;
492
493     case GPGME_ATTR_VALIDITY:
494       return uid ? validity_to_string (uid->validity) : NULL;
495
496     case GPGME_ATTR_KEY_CAPS:    
497       return subkey ? capabilities_to_string (subkey) : NULL;
498
499     case GPGME_ATTR_SERIAL:
500       return key->issuer_serial;
501
502     case GPGME_ATTR_ISSUER:
503       return idx ? NULL : key->issuer_name;
504
505     case GPGME_ATTR_CHAINID:
506       return key->chain_id;
507
508     default:
509       return NULL;
510     }
511 }
512
513
514 unsigned long
515 gpgme_key_get_ulong_attr (gpgme_key_t key, _gpgme_attr_t what,
516                           const void *reserved, int idx)
517 {
518   gpgme_subkey_t subkey;
519   gpgme_user_id_t uid;
520   int i;
521
522   if (!key || reserved || idx < 0)
523     return 0;
524
525   /* Select IDXth subkey.  */
526   subkey = key->subkeys;
527   for (i = 0; i < idx; i++)
528     {
529       subkey = subkey->next;
530       if (!subkey)
531         break;
532     }
533
534   /* Select the IDXth user ID.  */
535   uid = key->uids;
536   for (i = 0; i < idx; i++)
537     {
538       uid = uid->next;
539       if (!uid)
540         break;
541     }
542
543   switch (what)
544     {
545     case GPGME_ATTR_ALGO:
546       return subkey ? (unsigned long) subkey->pubkey_algo : 0;
547
548     case GPGME_ATTR_LEN:
549       return subkey ? (unsigned long) subkey->length : 0;
550
551     case GPGME_ATTR_TYPE:
552       return key->protocol == GPGME_PROTOCOL_CMS ? 1 : 0;
553
554     case GPGME_ATTR_CREATED:
555       return (subkey && subkey->timestamp >= 0)
556         ? (unsigned long) subkey->timestamp : 0;
557
558     case GPGME_ATTR_EXPIRE: 
559       return (subkey && subkey->expires >= 0)
560         ? (unsigned long) subkey->expires : 0;
561
562     case GPGME_ATTR_VALIDITY:
563       return uid ? uid->validity : 0;
564
565     case GPGME_ATTR_OTRUST:
566       return key->owner_trust;
567
568     case GPGME_ATTR_IS_SECRET:
569       return !!key->secret;
570
571     case GPGME_ATTR_KEY_REVOKED:
572       return subkey ? subkey->revoked : 0;
573
574     case GPGME_ATTR_KEY_INVALID:
575       return subkey ? subkey->invalid : 0;
576
577     case GPGME_ATTR_KEY_EXPIRED:
578       return subkey ? subkey->expired : 0;
579
580     case GPGME_ATTR_KEY_DISABLED:
581       return subkey ? subkey->disabled : 0;
582
583     case GPGME_ATTR_UID_REVOKED:
584       return uid ? uid->revoked : 0;
585
586     case GPGME_ATTR_UID_INVALID:
587       return uid ? uid->invalid : 0;
588
589     case GPGME_ATTR_CAN_ENCRYPT:
590       return key->can_encrypt;
591
592     case GPGME_ATTR_CAN_SIGN:
593       return key->can_sign;
594
595     case GPGME_ATTR_CAN_CERTIFY:
596       return key->can_certify;
597
598     default:
599       return 0;
600     }
601 }
602
603
604 static gpgme_key_sig_t
605 get_keysig (gpgme_key_t key, int uid_idx, int idx)
606 {
607   gpgme_user_id_t uid;
608   gpgme_key_sig_t sig;
609
610   if (!key || uid_idx < 0 || idx < 0)
611     return NULL;
612
613   uid = key->uids;
614   while (uid && uid_idx > 0)
615     {
616       uid = uid->next;
617       uid_idx--;
618     }
619   if (!uid)
620     return NULL;
621
622   sig = uid->signatures;
623   while (sig && idx > 0)
624     {
625       sig = sig->next;
626       idx--;
627     }
628   return sig;
629 }
630
631
632 const char *
633 gpgme_key_sig_get_string_attr (gpgme_key_t key, int uid_idx, _gpgme_attr_t what,
634                                const void *reserved, int idx)
635 {
636   gpgme_key_sig_t certsig = get_keysig (key, uid_idx, idx);
637
638   if (!certsig || reserved)
639     return NULL;
640
641   switch (what)
642     {
643     case GPGME_ATTR_KEYID:
644       return certsig->keyid;
645
646     case GPGME_ATTR_ALGO:    
647       return gpgme_pubkey_algo_name (certsig->pubkey_algo);
648
649     case GPGME_ATTR_USERID:
650       return certsig->uid;
651
652     case GPGME_ATTR_NAME:   
653       return certsig->name;
654
655     case GPGME_ATTR_EMAIL:
656       return certsig->email;
657
658     case GPGME_ATTR_COMMENT:
659       return certsig->comment;
660    
661     default:
662       return NULL;
663     }
664 }
665
666
667 unsigned long
668 gpgme_key_sig_get_ulong_attr (gpgme_key_t key, int uid_idx, _gpgme_attr_t what,
669                               const void *reserved, int idx)
670 {
671   gpgme_key_sig_t certsig = get_keysig (key, uid_idx, idx);
672
673   if (!certsig || reserved)
674     return 0;
675
676   switch (what)
677     {
678     case GPGME_ATTR_ALGO:    
679       return (unsigned long) certsig->pubkey_algo;
680
681     case GPGME_ATTR_CREATED: 
682       return certsig->timestamp < 0 ? 0L : (unsigned long) certsig->timestamp;
683
684     case GPGME_ATTR_EXPIRE: 
685       return certsig->expires < 0 ? 0L : (unsigned long) certsig->expires;
686
687     case GPGME_ATTR_KEY_REVOKED:
688       return certsig->revoked;
689
690     case GPGME_ATTR_KEY_INVALID:
691       return certsig->invalid;
692
693     case GPGME_ATTR_KEY_EXPIRED:
694       return certsig->expired;
695
696     case GPGME_ATTR_SIG_CLASS:
697       return certsig->class;
698
699     case GPGME_ATTR_SIG_STATUS:
700       return certsig->status;
701
702     default:
703       return 0;
704     }
705 }