/[winpt]/trunk/Src/wptKeyCache.cpp
ViewVC logotype

Contents of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 271 - (show annotations)
Sun Nov 5 08:57:45 2006 UTC (18 years, 3 months ago) by twoaday
File size: 26328 byte(s)


1 /* wptKeyCache.cpp- Caching for the pub- and the secring
2 * Copyright (C) 2001-2006 Timo Schulz
3 *
4 * This file is part of WinPT.
5 *
6 * WinPT is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * WinPT is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <windows.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <assert.h>
30 #include <gpgme.h>
31
32 #include "wptKeyCache.h"
33 #include "openpgp.h"
34 #include "wptNLS.h"
35 #include "wptErrors.h"
36 #include "wptW32API.h"
37 #include "wptGPG.h"
38 #include "wptTypes.h"
39 #include "wptCommonCtl.h"
40 #include "wptContext.h"
41 #include "wptKeyEdit.h"
42 #include "wptUTF8.h"
43
44
45 gpgme_error_t parse_keyserver_url (char **r_keyserver, unsigned short *r_port);
46
47 /* Attribute list which holds the image data. */
48 struct attr_list_s {
49 struct attr_list_s *next;
50 char *fpr; /* fingerprint of the key */
51 unsigned char *d; /* actual JPEG data. */
52 unsigned long octets; /* length of the data. */
53 unsigned int flags; /* status of the attribute. */
54 };
55 typedef struct attr_list_s *attr_list_t;
56
57
58 /* XXX: convert it to an inline function and place it in a header file. */
59 static unsigned char*
60 safe_uchar_alloc (size_t n)
61 {
62 unsigned char *p = new unsigned char[n];
63 if (!p)
64 BUG (0);
65 return p;
66 }
67
68
69 /* Free attribute list @ctx. */
70 void
71 free_attr_list (attr_list_t ctx)
72 {
73 attr_list_t n;
74
75 while (ctx) {
76 n = ctx->next;
77 free_if_alloc (ctx->fpr);
78 free_if_alloc (ctx->d);
79 free_if_alloc (ctx);
80 ctx = n;
81 }
82 }
83
84 /* Parse the attribute list in @fp and store it into @ctx.
85 Return value: number of parsed items. */
86 int
87 parse_attr_list (FILE *fp, const BYTE *data, DWORD datlen, attr_list_t *ctx)
88 {
89 attr_list_t c, t;
90 char buf[512], *p, *buffer;
91 int pos, n=0;
92
93 *ctx = NULL;
94 while (fgets (buf, 511, fp)) {
95 if (strstr (buf, "\r\n"))
96 buf[strlen (buf)-2]=0;
97 if (strstr (buf, "\n"))
98 buf[strlen (buf)-1]=0;
99 if (strlen (buf) < 2 || !strstr (buf, "ATTRIBUTE"))
100 continue;
101 buffer = buf+9+10;
102 pos = 0;
103 c = new attr_list_s;
104 if (!c)
105 BUG (0);
106 memset (c, 0, sizeof *c);
107
108 p = strtok (buffer, " ");
109 while (p != NULL) {
110 switch (pos) {
111 case 0:
112 c->fpr = m_strdup (p);
113 break;
114
115 case 1:
116 c->octets = strtoul (p, NULL, 10);
117 break;
118
119 case 7:
120 c->flags = strtoul (p, NULL, 10);
121 break;
122
123 default:
124 break;
125 }
126 pos++;
127 p = strtok (NULL, " ");
128 }
129 if (!*ctx)
130 *ctx = c;
131 else {
132 for (t = *ctx; t->next; t=t->next)
133 ;
134 t->next = c;
135 }
136 c->d = safe_uchar_alloc (c->octets);
137 memcpy (c->d, data, c->octets);
138 data += c->octets;
139 datlen -= c->octets;
140 n++;
141 }
142 /*assert (datlen == 0); */
143 return n;
144 }
145
146
147 static int
148 parse_attr_data (const char *keyid, attr_list_t *list)
149 {
150 gpgme_error_t err;
151 FILE *tmp;
152 BYTE *data;
153 char *status, tmpnam[MAX_PATH+1];
154 DWORD ndata = 0;
155
156 err = gpg_get_photoid_data (keyid, &status, &data, &ndata);
157 if (err)
158 return err;
159
160 get_temp_name (tmpnam, MAX_PATH, NULL);
161 tmp = fopen (tmpnam, "w+b");
162 if (ndata > 0 && tmp != NULL) {
163 fwrite (status, 1, strlen (status), tmp);
164 fflush (tmp);
165 rewind (tmp);
166 ndata = parse_attr_list (tmp, data, ndata, list);
167 }
168 else
169 *list = NULL;
170 if (tmp != NULL) {
171 fclose (tmp);
172 DeleteFile (tmpnam);
173 }
174
175 safe_free (status);
176 safe_free (data);
177 return ndata;
178 }
179
180
181 /* Parse the secret keyring and retrieve some additional information
182 for each key which was found. */
183 static void
184 parse_secring (gpg_keycache_t cache, const char *kid, const char *secring)
185 {
186 PACKET *pkt;
187 PKT_secret_key *sk;
188 gpg_iobuf_t inp;
189 gpgme_error_t err;
190 gpgme_key_t key;
191 struct keycache_s *c=NULL;
192 char keyid[16+1];
193
194 inp = gpg_iobuf_open (secring);
195 if (!inp)
196 return;
197
198 gpg_iobuf_ioctl (inp, 3, 1, NULL);
199 pkt = (PACKET*)calloc (1, sizeof *pkt);
200 if (!pkt)
201 BUG (0);
202 gpg_init_packet (pkt);
203 while (gpg_parse_packet (inp, pkt) != -1) {
204 if (pkt->pkttype == PKT_SECRET_KEY) {
205 sk = pkt->pkt.secret_key;
206 /* XXX: key IDs of card public keys are wrong! */
207 _snprintf (keyid, sizeof (keyid)-1, "%08lX",
208 gpg_keyid_from_sk (sk, NULL));
209 if (kid && strcmp (kid, keyid) != 0)
210 goto next;
211 err = gpg_keycache_find_key2 (cache, keyid, 0, &key, &c);
212 if (err)
213 goto next;
214 c->gloflags.is_protected = sk->is_protected;
215 c->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
216 if (c->pubpart != NULL) {
217 c->pubpart->gloflags.is_protected = sk->is_protected;
218 c->pubpart->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
219 }
220 }
221 next:
222 gpg_free_packet (pkt);
223 gpg_init_packet (pkt);
224 }
225 safe_free (pkt);
226 gpg_iobuf_close (inp);
227 }
228
229
230 /* Update the photo image of a single key with the fingerprint
231 @fpr. The @dat struct contains the new item data. */
232 static gpgme_error_t
233 keycache_update_photo (gpg_keycache_t ctx, const char *fpr, attr_list_t dat)
234 {
235 struct keycache_s *fnd = NULL;
236 gpgme_key_t key;
237
238 gpg_keycache_find_key2 (ctx, fpr, 0, &key, &fnd);
239 if (!fnd)
240 return gpg_error (GPG_ERR_NOT_FOUND);
241 free_if_alloc (fnd->attrib.d);
242 fnd->attrib.flags = dat->flags;
243 fnd->attrib.len = dat->octets;
244 fnd->attrib.d = safe_uchar_alloc (dat->octets);
245 memcpy (fnd->attrib.d, dat->d, dat->octets);
246 return 0;
247 }
248
249
250 /* Update all photo images in the cache. */
251 static gpgme_error_t
252 keycache_update_photos (gpg_keycache_t ctx)
253 {
254 attr_list_t list=NULL, n;
255 DWORD ndata;
256
257 ndata = parse_attr_data (NULL, &list);
258 if (ndata < 1) {
259 free_attr_list (list);
260 return 0;
261 }
262
263 for (n=list; n; n=n->next)
264 keycache_update_photo (ctx, n->fpr, n);
265 free_attr_list (list);
266 return 0;
267 }
268
269
270 void
271 keycache_decode_uid (struct keycache_s *ctx)
272 {
273 gpgme_user_id_t u;
274 struct native_uid_s *n, *t;
275
276 for (u = ctx->key->uids; u; u = u->next) {
277 n = new native_uid_s;
278 if (!n)
279 BUG (0);
280 memset (n, 0, sizeof *n);
281 if (is_8bit_string (u->uid)) {
282 n->malloced = 1;
283 n->uid = utf8_to_native (u->uid);
284 if (u->name != NULL)
285 n->name = utf8_to_native (u->name);
286 if (u->email != NULL)
287 n->email = m_strdup (u->email);
288 if (u->comment != NULL)
289 n->comment = utf8_to_native (u->comment);
290 }
291 else {
292 n->malloced = 0;
293 n->uid = u->uid;
294 n->name = u->name;
295 n->comment = u->comment;
296 n->email = u->email;
297 }
298 n->signatures = u->signatures;
299 n->validity = u->validity;
300 n->revoked = u->revoked;
301 if (!ctx->uids)
302 ctx->uids = n;
303 else {
304 for (t = ctx->uids; t->next; t=t->next)
305 ;
306 t->next = n;
307 }
308 }
309 }
310
311
312 /* Store utf8 decoded user IDs in the code to avoid in-place decoding. */
313 static void
314 keycache_decode_uids (gpg_keycache_t ctx)
315 {
316 struct keycache_s *c;
317
318 for (c = ctx->item; c; c = c->next)
319 keycache_decode_uid (c);
320 }
321
322
323 static void
324 free_native_uids (struct native_uid_s **r_n)
325 {
326 struct native_uid_s *t;
327 struct native_uid_s *n = *r_n;
328
329 while (n != NULL) {
330 t = n->next;
331 if (n->malloced) {
332 free_if_alloc (n->uid);
333 free_if_alloc (n->name);
334 free_if_alloc (n->comment);
335 free_if_alloc (n->email);
336 }
337 free_if_alloc (n);
338 n = t;
339 }
340 *r_n = NULL;
341 }
342
343
344
345 /* Merge the information from the keyrings into the key cache structure. */
346 static gpgme_error_t
347 keycache_prepare2 (gpg_keycache_t ctx, const char *kid,
348 const char *pubring, const char *secring)
349 {
350 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
351 gpgme_key_t key = NULL;
352 gpg_iobuf_t inp;
353 PACKET *pkt;
354 struct keycache_s *c;
355 const BYTE *sym_prefs;
356 char keyid[16+1];
357 int key_seen = 0;
358 size_t nsym =0;
359
360 if (secring) {
361 parse_secring (ctx, kid, secring);
362 if (!pubring)
363 return 0;
364 }
365 inp = gpg_iobuf_open (pubring);
366 if (!inp)
367 return gpg_error (GPG_ERR_KEYRING_OPEN);
368 gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */
369
370 pkt = (PACKET*)calloc (1, sizeof * pkt);
371 if (!pkt)
372 BUG (0);
373 gpg_init_packet (pkt);
374 while (gpg_parse_packet (inp, pkt) != -1) {
375 if (pkt->pkttype == PKT_PUBLIC_KEY) {
376 strcpy (keyid, "");
377 key_seen = 1;
378 }
379 if (pkt->pkttype == PKT_SIGNATURE &&
380 pkt->pkt.signature->sig_class == 0x1F) {
381 if (pkt->pkt.signature->numrevkeys == 0)
382 goto next;
383 _snprintf (keyid, sizeof (keyid) -1, "%08X",
384 pkt->pkt.signature->keyid[1]);
385 if (kid && strcmp (kid, keyid) != 0)
386 goto next;
387 err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
388 if (err)
389 goto next;
390 c->gloflags.has_desig_rev = 1;
391 }
392 if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 && c != NULL) {
393 sym_prefs = gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,
394 SIGSUBPKT_PREF_SYM, &nsym);
395 if (!sym_prefs)
396 goto next;
397 _snprintf (keyid, sizeof (keyid) - 1, "%08X",
398 pkt->pkt.signature->keyid[1]);
399 if (kid && strcmp (kid, keyid) != 0)
400 goto next;
401 err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
402 if (err || !c)
403 goto next;
404 if (c->sym_prefs) // only use the prefs from the primary uid.
405 goto next;
406 else if (nsym > 0) {
407 c->sym_prefs = safe_uchar_alloc (nsym+1);
408 memset (c->sym_prefs, 0, nsym+1);
409 memcpy (c->sym_prefs, sym_prefs, nsym);
410 }
411 }
412 next:
413 gpg_free_packet (pkt);
414 gpg_init_packet(pkt);
415 }
416
417 safe_free (pkt);
418 gpg_iobuf_close (inp);
419 return err;
420 }
421
422
423 gpgme_error_t
424 gpg_keycache_prepare (gpg_keycache_t ctx, const char *pubr, const char *secr)
425 {
426 return keycache_prepare2 (ctx, NULL, pubr, secr);
427 }
428
429 gpgme_error_t
430 gpg_keycache_prepare_single (gpg_keycache_t ctx, const char *keyid,
431 const char *pubr, const char *secr)
432 {
433 if (!strncmp (keyid, "0x", 2))
434 keyid += 2;
435 return keycache_prepare2 (ctx, keyid, pubr, secr);
436 }
437
438
439 /* Create new keycache object and return it in @r_ctx.
440 Return value: 0 on success. */
441 gpgme_error_t
442 gpg_keycache_new (gpg_keycache_t *r_ctx)
443 {
444 gpg_keycache_t ctx;
445
446 if (!r_ctx)
447 return gpg_error (GPG_ERR_INV_ARG);
448 ctx = new gpg_keycache_s;
449 if (!ctx)
450 BUG (0);
451 memset (ctx, 0, sizeof *ctx);
452 ctx->secret = 0;
453 ctx->pos = 0;
454 *r_ctx = ctx;
455 return 0;
456 }
457
458
459 void
460 gpg_keycache_item_release (struct keycache_s *c)
461 {
462 if (c->key)
463 gpgme_key_release (c->key);
464 c->key = NULL;
465 if (c->rev != NULL)
466 gpg_desig_rev_release (c->rev);
467 c->rev = NULL;
468 free_if_alloc (c->pref_keyserver);
469 free_if_alloc (c->sym_prefs);
470 free_if_alloc (c->attrib.d);
471 free_if_alloc (c->card_type);
472 free_native_uids (&c->uids);
473 free_if_alloc (c);
474 }
475
476
477 /* Release keycache object @ctx. */
478 void
479 gpg_keycache_release (gpg_keycache_t ctx)
480 {
481 struct keycache_s *c, *c2;
482
483 if (!ctx)
484 return;
485
486 for (c = ctx->item; c; c = c2) {
487 c2 = c->next;
488 gpg_keycache_item_release (c);
489 }
490 free_if_alloc (ctx);
491 }
492
493
494 /* Set (progress) callback for the given keycache object.
495 @ctx the keycache
496 @cb the callback function
497 @cb_value1 opaque value which is passed to the callback.
498 @cb_value2 see @cb_value1. */
499 void
500 gpg_keycache_set_cb (gpg_keycache_t ctx,
501 void (*cb)(void *, const char *, int, int, int),
502 void * cb_value1, int cb_value2)
503 {
504 if (!ctx)
505 return;
506 ctx->cb = cb;
507 ctx->cb_value = cb_value1;
508 ctx->cb_value2 = cb_value2;
509 }
510
511
512 /* Add @key to the cache @ctx. @opaque return the key cache context as a void*.
513 Return value: 0 on success. */
514 gpgme_error_t
515 gpg_keycache_add_key (gpg_keycache_t ctx, gpgme_key_t key, void **opaque)
516 {
517 struct keycache_s *c, *n1;
518
519 if (!ctx)
520 return gpg_error (GPG_ERR_INV_ARG);
521
522 c = new keycache_s;
523 if (!c)
524 BUG (0);
525 memset (c, 0, sizeof *c);
526 c->gloflags.is_protected = 1; /*default: assume protection. */
527 c->key = key;
528 if (!ctx->item)
529 ctx->item = c;
530 else {
531 for (n1 = ctx->item; n1 && n1->next; n1 = n1->next)
532 ;
533 n1->next = c;
534 }
535 if (opaque)
536 *opaque = c;
537 return 0;
538 }
539
540
541
542 #define has_keyid_len(pattern) (\
543 strlen (pattern) == 8 || strlen (pattern) == 10 || \
544 strlen (pattern) == 16 || strlen (pattern) == 18)
545
546
547 gpgme_error_t
548 gpg_keycache_find_key2 (gpg_keycache_t ctx, const char *pattern, int flags,
549 gpgme_key_t *r_key, struct keycache_s **r_item)
550 {
551 struct keycache_s *c;
552 gpgme_subkey_t s;
553 gpgme_user_id_t u;
554 gpgme_key_t key;
555 const char *kid;
556
557 if (!ctx || !r_key)
558 return gpg_error (GPG_ERR_INV_ARG);
559
560 if (strstr (pattern, "0x"))
561 pattern += 2;
562
563 /* Sometimes a subkey has no valid fpr. As a kludge we convert v4
564 fingerprints into the 64-bit keyid. */
565 if (strlen (pattern) == 40 && isxdigit (*pattern))
566 pattern += 32;
567
568 /* XXX: this code is very slow, revamp it and use hash tables whenever
569 it is possible. */
570 for (c = ctx->item; c; c = c->next) {
571 key = c->key;
572 assert (key->_refs >= 1);
573 for (s = key->subkeys; s; s = s->next) {
574 for (u = key->uids; u; u = u->next) {
575 if (u->name && stristr (u->name, pattern)) {
576 if (r_item)
577 *r_item = c;
578 *r_key = flags? c->pubpart->key : c->key;
579 return 0;
580 }
581 }
582 if (has_keyid_len (pattern))
583 kid = s->keyid;
584 else
585 kid = s->fpr;
586 if (kid && stristr (kid, pattern)) {
587 if (r_item)
588 *r_item = c;
589 *r_key = flags? c->pubpart->key : c->key;
590 return 0;
591 }
592 }
593 }
594 *r_key = NULL;
595 return gpg_error (GPG_ERR_INTERNAL);
596 }
597
598
599 gpgme_error_t
600 gpg_keycache_find_key (gpg_keycache_t ctx, const char *pattern,
601 int flags, gpgme_key_t *r_key)
602 {
603 return gpg_keycache_find_key2 (ctx, pattern, flags, r_key, NULL);
604 }
605
606
607 /* Reload a photo image of a single key with the keyid @keyid.
608 Return value: 0 on success. */
609 static gpgme_error_t
610 keycache_reload_photo (gpg_keycache_t ctx, const char *keyid)
611 {
612 attr_list_t list;
613
614 if (parse_attr_data (keyid, &list) < 1) {
615 free_attr_list (list);
616 return 0;
617 }
618 keycache_update_photo (ctx, list->fpr, list);
619 free_attr_list (list);
620 return 0;
621 }
622
623
624 /* Return the next key which was updated. Before it is
625 returned the update flag is cleared.
626 @r_status is 1 for a new key and 2 for an updated key.
627 Return value: 0 on success. */
628 gpgme_error_t
629 gpg_keycache_next_updated_key (gpg_keycache_t ctx,
630 struct keycache_s **r_obj,
631 int *r_status)
632 {
633 struct keycache_s *c;
634
635 for (c = ctx->item; c; c = c->next) {
636 if (c->flags != 0) {
637 *r_status = c->flags;
638 *r_obj = c;
639 c->flags = 0; /* reset update flag. */
640 return 0;
641 }
642 }
643 return gpg_error (GPG_ERR_NOT_FOUND);
644 }
645
646
647 /* Helper to retrieve a GPG key. */
648 static gpgme_error_t
649 get_gpg_key (const char *keyid, int is_sec, gpgme_key_t *r_key)
650 {
651 gpgme_ctx_t ctx;
652 gpgme_error_t err;
653
654 err = gpgme_new (&ctx);
655 if (err)
656 return err;
657 gpgme_set_keylist_mode (ctx, GPGME_KEYLIST_MODE_SIGS);
658 err = gpgme_get_key (ctx, keyid, r_key, is_sec);
659 gpgme_release (ctx);
660 return err;
661 }
662
663
664 /* Fetch a key directly from gpg but without adding
665 it to the key cache. Caller must free @r_ctx. */
666 gpgme_error_t
667 gpg_keycache_fetch_key (const char *keyid, int is_sec,
668 gpgme_key_t *r_key, struct keycache_s **r_c)
669 {
670 gpgme_error_t err;
671 gpgme_key_t key;
672 struct keycache_s *c;
673
674 *r_key = NULL;
675 *r_c = NULL;
676 err = get_gpg_key (keyid, is_sec, &key);
677 if (err)
678 return err;
679
680 c = new keycache_s;
681 if (!c)
682 BUG (0);
683 memset (c, 0, sizeof *c);
684 c->gloflags.is_protected = 1; /*default: assume protection. */
685 c->key = key;
686 keycache_decode_uid (c);
687 *r_key = key;
688 *r_c = c;
689 return 0;
690 }
691
692
693 /* Update the key with the keyid @key in the key cache.
694 If the key does not exist, it is added otherwise all
695 parts are first freed and then replaced with the updated data. */
696 gpgme_error_t
697 gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,
698 void *opaque, const char *keyid)
699 {
700 gpgme_key_t key=NULL, fndkey=NULL;
701 gpgme_error_t err;
702 struct keycache_s *c = NULL, *c_new=NULL;
703 gpg_keycache_t pub = (gpg_keycache_t)opaque;
704
705 err = get_gpg_key (keyid, is_sec, &key);
706 if (err)
707 return err;
708 err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);
709 if (!err && c != NULL) {
710 log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);
711 gpgme_key_release (fndkey);
712 c->key = key;
713 c->flags = KC_FLAG_UPD;
714 if (is_sec && pub != NULL &&
715 !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {
716 log_debug ("keycache update: set public part %p\r\n", fndkey);
717 c->pubpart->key = fndkey;
718 }
719 /* XXX: this is also called for keys without a photo-id. */
720 keycache_reload_photo (ctx, keyid);
721 }
722 else {
723 log_debug ("keycache add: sync public part\r\n");
724 if (is_sec)
725 gpg_keycache_find_key2 (pub, keyid, 0, &fndkey, &c_new);
726 gpg_keycache_add_key (ctx, key, (void **)&c);
727 if (c != NULL && is_sec) {
728 log_debug ("keycache add: keyid=%s %p %p\r\n", keyid, c, fndkey);
729 c->pubpart = c_new;
730 if (c_new != NULL) {
731 c->pubpart->key = fndkey;
732 c->gloflags.is_protected = c_new->gloflags.is_protected;
733 c->gloflags.divert_to_card = c_new->gloflags.divert_to_card;
734 }
735 }
736 if (c != NULL)
737 c->flags = KC_FLAG_ADD;
738 }
739
740 /* refresh utf8 user ID list. */
741 if (c != NULL && c->key) {
742 free_native_uids (&c->uids);
743 keycache_decode_uid (c);
744 }
745
746 return 0;
747 }
748
749
750 /* Delete a key from the cache @ctx with the pattern @pattern.
751 Return value: 0 on success. */
752 gpgme_error_t
753 gpg_keycache_delete_key (gpg_keycache_t ctx, const char *pattern)
754 {
755 struct keycache_s *itm = NULL, *c;
756 gpgme_key_t key;
757 gpgme_error_t rc;
758
759 if (!ctx)
760 return gpg_error (GPG_ERR_INV_ARG);
761 rc = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
762 if (rc)
763 return rc;
764
765 c = ctx->item;
766 if (!c) /* empty */
767 return 0;
768 else if (c->next == NULL) {
769 if (itm->key)
770 gpgme_key_release (itm->key);
771 itm->key = NULL;
772 free_if_alloc (itm);
773 /* the cache has no other items, so we set the context to NULL
774 to indicate that the entire cache is empty. */
775 ctx->item = NULL;
776 }
777 else {
778 for (; c != NULL; c = c->next) {
779 if (c->next == itm)
780 break;
781 }
782 assert (c != NULL); /* XXX: sometimes access violation. */
783 c->next = c->next->next;
784 if (itm->key)
785 gpgme_key_release (itm->key);
786 itm->key = NULL;
787 free_if_alloc (itm);
788 }
789 return 0;
790 }
791
792
793 /* Initialize the given cache @ctx. If @pattern is NULL, the entire keyring
794 will be added to the cache. @secret is 1 if the source is the secret keyring.
795 Return value: 0 on success. */
796 gpgme_error_t
797 gpg_keycache_init (gpg_keycache_t ctx, const char *pattern, int secret)
798 {
799 gpgme_error_t err;
800 gpgme_ctx_t c;
801 gpgme_key_t key;
802 int count = 0;
803
804 if (!ctx)
805 return gpg_error (GPG_ERR_INV_ARG);
806
807 err = gpgme_new (&c);
808 if (err)
809 return err;
810
811 /* XXX: GPGME_KEYLIST_MODE_SIG_NOTATIONS causes an internal error! */
812 gpgme_set_keylist_mode (c, GPGME_KEYLIST_MODE_SIGS);
813 err = gpgme_op_keylist_start (c, pattern, secret);
814 while(!err) {
815 err = gpgme_op_keylist_next (c, &key);
816 if (!err)
817 err = gpg_keycache_add_key (ctx, key, NULL);
818 if (ctx->cb)
819 ctx->cb (ctx->cb_value, _("Load GPG Keyrings..."), 0,
820 count++, ctx->cb_value2);
821 }
822 if (gpgme_err_code (err) == GPG_ERR_EOF)
823 err = gpg_error (GPG_ERR_NO_ERROR);
824 keycache_update_photos (ctx);
825 keycache_decode_uids (ctx);
826 gpgme_op_keylist_end (c);
827 gpgme_release (c);
828 return err;
829 }
830
831
832 /* Return 1 if we can assume that the actual private key is
833 stored on a smart card. This is not bullet proof, but the
834 card provides 3 keys (RSA) and each key for a different purpose. */
835 static int
836 key_divert_to_card (gpgme_key_t key)
837 {
838 gpgme_subkey_t k;
839 int n=0;
840 int can_auth = 0, can_encr = 0;
841
842 for (k = key->subkeys; k; k = k->next) {
843 n++;
844 if (k->pubkey_algo != GPGME_PK_RSA || k->length != 1024) {
845 return 0;
846 break;
847 }
848 if (k->can_authenticate)
849 can_auth++;
850 if (k->can_encrypt)
851 can_encr++;
852 }
853 if (n >= 3 && can_auth >= 1 && can_encr >= 1)
854 return 1;
855 return 0;
856 }
857
858
859 static unsigned char*
860 copy_uid_prefs (const unsigned char *prefs)
861 {
862 unsigned char *p;
863 size_t pos=0;
864
865 while (prefs[pos] != 0)
866 pos++;
867 p = safe_uchar_alloc (pos+1);
868 memset (p, 0, pos+1);
869 memcpy (p, prefs, pos);
870 return p;
871 }
872
873
874 /* Sync the secret and the public key cache information. */
875 gpgme_error_t
876 gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)
877 {
878 struct keycache_s *c, *c_sec;
879 gpgme_key_t key;
880
881 if (!pub || !sec)
882 return gpg_error (GPG_ERR_INV_ARG);
883
884 for (c=sec->item; c; c=c->next) {
885 if (!gpg_keycache_find_key2 (pub, c->key->subkeys->keyid, 0,
886 &key, &c_sec)) {
887 c_sec->gloflags.is_protected = c->gloflags.is_protected;
888 c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;
889 if (!c->gloflags.divert_to_card)
890 c->gloflags.divert_to_card = key_divert_to_card (key);
891 if (c_sec->sym_prefs)
892 c->sym_prefs = copy_uid_prefs (c_sec->sym_prefs);
893 c->pubpart = c_sec;
894 c->pubpart->key = key;
895 }
896 }
897 return 0;
898 }
899
900
901 /* Rewind the given cache @ctx to the begin. */
902 void
903 gpg_keycache_rewind (gpg_keycache_t ctx)
904 {
905 if (ctx)
906 ctx->pos = 0;
907 }
908
909
910
911 /* Return the number of elements in the cache @ctx. */
912 int
913 gpg_keycache_get_size (gpg_keycache_t ctx)
914 {
915 struct keycache_s *c;
916 int count = 0;
917
918 if (!ctx)
919 return 0;
920 for (c = ctx->item; c; c = c->next)
921 count++;
922 return count;
923 }
924
925
926 static gpgme_error_t
927 keycache_next_key (gpg_keycache_t ctx, int flags,
928 struct keycache_s **c, gpgme_key_t *r_key)
929 {
930 if (!ctx || !r_key)
931 return gpg_error (GPG_ERR_INV_ARG);
932
933 if (!ctx->pos)
934 ctx->tmp = ctx->item;
935
936 if (!ctx->tmp || !ctx->tmp->key) {
937 ctx->pos = 0;
938 *r_key = NULL;
939 return gpg_error (GPG_ERR_EOF);
940 }
941 if (ctx->tmp->flags != 0)
942 ctx->tmp->flags = 0; /* reset the 'updated' status. */
943
944 /* it might be possible there is no public key. */
945 if (flags && ctx->tmp->pubpart == NULL)
946 flags = 0;
947 *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;
948 *c = ctx->tmp;
949 ctx->tmp = ctx->tmp->next;
950 ctx->pos++;
951
952 return 0;
953 }
954
955
956 /* Return the next key from the cache @ctx. The key will be returned
957 in @r_key. @flags can contain additional flags.
958 Return value: 0 on success. */
959 gpgme_error_t
960 gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)
961 {
962 struct keycache_s *c=NULL;
963 gpgme_error_t err;
964
965 err = keycache_next_key (ctx, flags, &c, r_key);
966 return err;
967 }
968
969
970 gpgme_error_t
971 gpg_keycache_next_key2 (gpg_keycache_t ctx, int flags,
972 struct keycache_s **c, gpgme_key_t *r_key)
973 {
974 return keycache_next_key (ctx, flags, c, r_key);
975 }
976
977
978 /* Search for a key with the pattern @pattern and mark
979 this key as the default signing key if found.
980 Return value: 0 on success. */
981 gpgme_error_t
982 gpg_keycache_set_default_key (gpg_keycache_t ctx,
983 const char *pattern)
984 {
985 gpgme_error_t err;
986 gpgme_key_t key;
987 struct keycache_s *itm;
988
989 err = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
990 if (err)
991 return err;
992
993 if (itm)
994 itm->default_key = 1;
995 return 0;
996 }
997
998 /* Return the default key from the cache. If no was
999 marked before, NULL is returned in @r_key.
1000 Return value: 0 on success. */
1001 gpgme_error_t
1002 gpg_keycache_get_default_key (gpg_keycache_t ctx,
1003 gpgme_key_t *r_key)
1004 {
1005 struct keycache_s *itm;
1006
1007 *r_key = NULL;
1008 for (itm = ctx->item; itm; itm = itm->next) {
1009 if (itm->default_key) {
1010 *r_key = itm->key;
1011 break;
1012 }
1013 }
1014 if (!*r_key)
1015 return gpgme_error (GPG_ERR_NOT_FOUND);
1016 return 0;
1017 }
1018
1019
1020 static gpgme_error_t
1021 decode_subpacket (const char *subpkt_data, int *type,
1022 char **out, WORD *outlen)
1023 {
1024 char tmp[128], *val;
1025 char *enc = NULL;
1026 size_t pos = 0;
1027
1028 /* example: spk:24:1:21:http%3A//subkeys.pgp.de */
1029 *outlen = 0;
1030 *out = NULL;
1031
1032 if (strncmp (subpkt_data, "spk:", 4))
1033 return gpg_error (GPG_ERR_NO_DATA);
1034
1035 /* XXX: do not use static buffer sizes. */
1036 strncpy (tmp, subpkt_data, DIM (tmp)-4);
1037 val = strtok (tmp, ":");
1038 while (val != NULL) {
1039 switch (pos++) {
1040 case 0:
1041 break;
1042
1043 case 1:
1044 if (type)
1045 *type = atoi (val);
1046 break;
1047
1048 case 2:
1049 break;
1050
1051 case 3:
1052 *outlen = atoi (val);
1053 break;
1054
1055 case 4:
1056 enc = m_strdup (val);
1057 break;
1058 }
1059 val = strtok (NULL, ":");
1060 }
1061 if (!enc)
1062 return gpg_error (GPG_ERR_NO_DATA);
1063 unhexify_buffer (enc, out);
1064 free_if_alloc (enc);
1065 return 0;
1066 }
1067
1068
1069 /* If the attribute given in @attr is not set in the
1070 key cache object, try to update it. */
1071 gpgme_error_t
1072 gpg_keycache_update_attr (struct keycache_s *item,
1073 int attr, int force)
1074 {
1075 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
1076 char *val = NULL;
1077 WORD n = 0;
1078
1079 switch (attr) {
1080 case KC_ATTR_PREFSYM:
1081 if (!force && item->sym_prefs)
1082 break;
1083 free_if_alloc (item->sym_prefs);
1084 err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
1085 if (!err && val != NULL)
1086 err = decode_subpacket (val, NULL, (char**)&item->sym_prefs, &n);
1087 break;
1088
1089 case KC_ATTR_PREFKSERV:
1090 if (!force && item->pref_keyserver)
1091 break;
1092 free_if_alloc (item->pref_keyserver);
1093 err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
1094 if (!err && val != NULL)
1095 err = decode_subpacket (val, NULL, &item->pref_keyserver, &n);
1096 if (!err && item->pref_keyserver)
1097 err = parse_keyserver_url (&item->pref_keyserver,
1098 &item->pref_keyserver_port);
1099 break;
1100 }
1101 safe_free (val);
1102 return err;
1103 }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26