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

Contents of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 340 - (show annotations)
Sun Nov 27 13:15:07 2011 UTC (13 years, 3 months ago) by twoaday
File size: 26148 byte(s)


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26