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

Contents of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 226 - (show annotations)
Mon Jun 12 13:40:21 2006 UTC (18 years, 8 months ago) by twoaday
File size: 26131 byte(s)
Prepare new release.


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26