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