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

Contents of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 217 - (show annotations)
Mon May 22 14:21:39 2006 UTC (18 years, 9 months ago) by twoaday
File size: 25782 byte(s)
2005-05-20  Timo Schulz  <ts@g10code.de>
                                                                                
        * wptKeyPropsDlg.cpp (keyprops_load_photo): avoid expensive
        process call when no photo is available.
        (keyprops_dlg_proc): avoid static data.
        * wptFileManager.cpp (fm_add_sig_stat): Free memory in case
        of on demand key requests.
        (show_verify_result): Likewise.
        (secret_key_available): Likewise.
        (fm_decrypt, fm_sign): Handle the new on demand key request
        mode and free all memory.


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26