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