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

Contents of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 121 - (show annotations)
Mon Dec 12 11:19:56 2005 UTC (19 years, 2 months ago) by twoaday
File size: 15234 byte(s)
2005-12-11  Timo Schulz  <ts@g10code.com>
 
        * wptW32API.cpp (get_file_version): New.
        * wptGPGUtil.cpp (create_process): Always hide window.
        * wptClipEditDlg.cpp (clipedit_dlg_proc): Use 'Close'
        instead of 'Exit'.
        * wptKeyManager.cpp (km_http_import): New filename
        generation code.
        (km_send_to_mail_recipient): Cleanups.
        * wptKeyEditDlg.cpp (showpref_dlg_proc): Localize dialog.
        * wptKeyManagerDlg.cpp (update_ui_items): Handle the case
        when multiple keys are selected.
        (popup_multiple): New.
        * WinPT.cpp (WinMain): Check that the PTD.dll and WinPT.exe
        file versions are equal. Rewrote --keymanager code.
         
Removed temporary w32gpgme dirctory, all code is now in Src.
Changed configure files.


1 /* wptKeyCache.cpp- Caching for the pub- and the secring
2 * Copyright (C) 2001-2005 Timo Schulz
3 *
4 * This file is part of MyGPGME.
5 *
6 * MyGPGME 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 * MyGPGME 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 <malloc.h>
29 #include <ctype.h>
30 #include <assert.h>
31 #include <gpgme.h>
32
33 #include "wptKeyCache.h"
34 #include "openpgp.h"
35 #include "wptNLS.h"
36 #include "wptErrors.h"
37 #include "wptW32API.h"
38
39
40 #if 0
41 /* convert a binary buffer into its hex representation. */
42 static void
43 buffer_to_string (char *dst, size_t dlen, const byte *buf, size_t nbytes)
44 {
45 char dig[3];
46 size_t i;
47
48 memset (dst, 0, dlen);
49 for (i = 0; i < nbytes && dlen > 0; i++) {
50 sprintf (dig, "%02X", buf[i]);
51 strcat (dst, dig);
52 dlen -= 2;
53 }
54 }
55 #endif
56
57
58 /* Parse the secret keyring and retrieve some additional information
59 for each key which was found. */
60 static void
61 parse_secring (gpg_keycache_t cache, const char *kid, const char *secring)
62 {
63 PACKET *pkt = (PACKET*)calloc (1, sizeof *pkt);
64 PKT_secret_key *sk;
65 gpg_iobuf_t inp;
66 gpgme_error_t err;
67 gpgme_key_t key;
68 struct keycache_s *c=NULL;
69 char keyid[16+1];
70
71 inp = gpg_iobuf_open (secring);
72 if (!inp) {
73 safe_free (pkt);
74 return;
75 }
76 gpg_iobuf_ioctl (inp, 3, 1, NULL);
77 gpg_init_packet (pkt);
78 while (gpg_parse_packet (inp, pkt) != -1) {
79 if (pkt->pkttype == PKT_SECRET_KEY) {
80 sk = pkt->pkt.secret_key;
81 /* XXX: key IDs of card public keys are wrong! */
82 _snprintf (keyid, sizeof (keyid)-1, "%08lX",
83 gpg_keyid_from_sk (sk, NULL));
84 if (kid && strcmp (kid, keyid) != 0)
85 goto next;
86 err = gpg_keycache_find_key2 (cache, keyid, 0, &key, &c);
87 if (err)
88 goto next;
89 c->gloflags.is_protected = sk->is_protected;
90 c->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
91 if (c->pubpart != NULL) {
92 c->pubpart->gloflags.is_protected = sk->is_protected;
93 c->pubpart->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
94 }
95 }
96 next:
97 gpg_free_packet (pkt);
98 gpg_init_packet (pkt);
99 }
100 safe_free (pkt);
101 gpg_iobuf_close (inp);
102 }
103
104
105 /* Merge the information from the keyrings into the key cache structure. */
106 gpgme_error_t
107 keycache_prepare2 (gpg_keycache_t ctx, const char *kid,
108 const char *pubring, const char *secring)
109 {
110 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
111 gpgme_key_t key = NULL;
112 gpg_iobuf_t inp;
113 PACKET *pkt = (PACKET*)calloc (1, sizeof * pkt);
114 struct keycache_s *c;
115 const byte *sym_prefs;
116 char keyid[16+1], *id = NULL;
117 int key_seen = 0;
118 size_t nsym =0;
119
120 if (secring) {
121 parse_secring (ctx, kid, secring);
122 if (!pubring) {
123 safe_free(pkt);
124 return 0;
125 }
126 }
127 inp = gpg_iobuf_open (pubring);
128 if (!inp) {
129 safe_free( pkt );
130 return gpg_error (GPG_ERR_KEYRING_OPEN);
131 }
132 gpg_iobuf_ioctl( inp, 3, 1, NULL ); /* disable cache */
133
134 gpg_init_packet( pkt );
135 while (gpg_parse_packet (inp, pkt) != -1) {
136 if (pkt->pkttype == PKT_PUBLIC_KEY) {
137 strcpy (keyid, "");
138 key_seen = 1;
139 }
140
141 if (pkt->pkttype == PKT_SIGNATURE && pkt->pkt.signature->sig_class == 0x1F) {
142 if (pkt->pkt.signature->numrevkeys == 0)
143 goto next;
144 _snprintf (keyid, sizeof keyid -1, "%08X", pkt->pkt.signature->keyid[1]);
145 if (kid && strcmp (kid, keyid) != 0)
146 goto next;
147 err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
148 if (err)
149 goto next;
150 c->gloflags.has_desig_rev = 1;
151 }
152 if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 ) {
153 sym_prefs=gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,
154 SIGSUBPKT_PREF_SYM, &nsym);
155 if (sym_prefs == NULL)
156 goto next;
157 _snprintf (keyid, sizeof keyid - 1, "%08X", pkt->pkt.signature->keyid[1]);
158 if (kid && strcmp (kid, keyid) != 0)
159 goto next;
160 err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
161 if (err)
162 goto next;
163 else if (nsym > 0) {
164 c->sym_prefs = (unsigned char*)calloc (1, nsym+1);
165 if (!c->sym_prefs)
166 return gpg_error (GPG_ERR_ENOMEM);
167 memcpy (c->sym_prefs, sym_prefs, nsym);
168 }
169 }
170 if (pkt->pkttype == PKT_USER_ID) {
171 if (id)
172 free (id);
173 id = strdup (pkt->pkt.user_id->name);
174 if (!id) {
175 err = gpg_error (GPG_ERR_ENOMEM);
176 goto fail;
177 }
178 }
179 if ((pkt->pkttype == PKT_USER_ID || pkt->pkttype == PKT_ATTRIBUTE)
180 && pkt->pkt.user_id->attrib_data && key) {
181 PKT_user_id *uid = pkt->pkt.user_id;
182 c->attrib.used = 1;
183 c->attrib.len = uid->attrib_len;
184 c->attrib.d = (unsigned char*)calloc (1, uid->attrib_len + 1);
185 if (!c->attrib.d) {
186 err = gpg_error (GPG_ERR_ENOMEM);
187 goto fail;
188 }
189 memcpy (c->attrib.d, uid->attrib_data, uid->attrib_len);
190 key = NULL;
191 c = NULL;
192 }
193 next:
194 gpg_free_packet (pkt);
195 gpg_init_packet(pkt);
196 }
197
198 fail:
199 safe_free (id);
200 safe_free (pkt);
201 gpg_iobuf_close (inp);
202 return err;
203 }
204
205
206 gpgme_error_t
207 gpg_keycache_prepare (gpg_keycache_t ctx, const char *pubr, const char *secr)
208 {
209 return keycache_prepare2 (ctx, NULL, pubr, secr);
210 }
211
212 gpgme_error_t
213 gpg_keycache_prepare_single (gpg_keycache_t ctx, const char *keyid,
214 const char *pubr, const char *secr)
215 {
216 if (!strncmp (keyid, "0x", 2))
217 keyid += 2;
218 return keycache_prepare2 (ctx, keyid, pubr, secr);
219 }
220
221
222 /* Create new keycache object and return it in @r_ctx.
223 Return value: 0 on success. */
224 gpgme_error_t
225 gpg_keycache_new (gpg_keycache_t *r_ctx)
226 {
227 gpg_keycache_t ctx;
228
229 if (!r_ctx)
230 return gpg_error (GPG_ERR_INV_ARG);
231 ctx = (gpg_keycache_t)calloc (1, sizeof *ctx);
232 if (!ctx)
233 return gpg_error (GPG_ERR_ENOMEM);
234 ctx->secret = 0;
235 ctx->pos = 0;
236 *r_ctx = ctx;
237 return 0;
238 }
239
240
241 /* Release keycache object @ctx. */
242 void
243 gpg_keycache_release (gpg_keycache_t ctx)
244 {
245 struct keycache_s *c, *c2;
246
247 if (!ctx)
248 return;
249
250 for (c = ctx->item; c; c = c2) {
251 c2 = c->next;
252 gpgme_key_release (c->key);
253 c->key = NULL;
254 if (c->sym_prefs)
255 free (c->sym_prefs);
256 c->sym_prefs = NULL;
257 if (c->attrib.d)
258 free (c->attrib.d);
259 c->attrib.d = NULL;
260 if (c->card_type)
261 free (c->card_type);
262 free (c);
263 }
264 if (ctx)
265 free (ctx);
266 }
267
268
269 /* Set (progress) callback for the given keycache object.
270 @ctx the keycache
271 @cb the callback function
272 @cb_value1 opaque value which is passed to the callback.
273 @cb_value2 see @cb_value1. */
274 void
275 gpg_keycache_set_cb (gpg_keycache_t ctx,
276 void (*cb)(void *, const char *, int, int, int),
277 void * cb_value1, int cb_value2)
278 {
279 if (!ctx)
280 return;
281 ctx->cb = cb;
282 ctx->cb_value = cb_value1;
283 ctx->cb_value2 = cb_value2;
284 }
285
286
287 /* Add @key to the cache @ctx. @opaque return the key cache context as a void*.
288 Return value: 0 on success. */
289 gpgme_error_t
290 gpg_keycache_add_key (gpg_keycache_t ctx, gpgme_key_t key, void **opaque)
291 {
292 struct keycache_s *c, *n1;
293
294 if (!ctx)
295 return gpg_error (GPG_ERR_INV_ARG);
296
297 c = (struct keycache_s*)calloc (1, sizeof *c);
298 if (!c)
299 return gpg_error (GPG_ERR_ENOMEM);
300 c->gloflags.is_protected = 1; /*default: assume protection. */
301 c->key = key;
302 if (!ctx->item)
303 ctx->item = c;
304 else {
305 for (n1 = ctx->item; n1 && n1->next; n1 = n1->next)
306 ;
307 n1->next = c;
308 }
309 if (opaque)
310 *opaque = c;
311 return 0;
312 }
313
314
315
316 #define has_keyid_len(pattern) (\
317 strlen (pattern) == 8 || strlen (pattern) == 10 || \
318 strlen (pattern) == 16 || strlen (pattern) == 18)
319
320
321 gpgme_error_t
322 gpg_keycache_find_key2 (gpg_keycache_t ctx, const char *pattern, int flags,
323 gpgme_key_t *r_key, struct keycache_s **r_item)
324 {
325 struct keycache_s *c;
326 gpgme_subkey_t s;
327 gpgme_user_id_t u;
328 gpgme_key_t key;
329 const char *kid;
330
331 if (!ctx || !r_key)
332 return gpg_error (GPG_ERR_INV_ARG);
333
334 if (strstr (pattern, "0x"))
335 pattern += 2;
336
337 /* Sometimes a subkey has no valid fpr. As a kludge we convert v4
338 fingerprints into the 64-bit keyid. */
339 if (strlen (pattern) == 40 && isxdigit (*pattern))
340 pattern += 32;
341
342 /* XXX: this code is very slow, revamp it and use hash tables whenever
343 it is possible. */
344 for (c = ctx->item; c; c = c->next) {
345 key = c->key;
346 assert (key->_refs >= 1);
347 for (s = key->subkeys; s; s = s->next) {
348 for (u = key->uids; u; u = u->next) {
349 if (u->name && stristr (u->name, pattern)) {
350 if (r_item)
351 *r_item = c;
352 *r_key = flags? c->pubpart->key : c->key;
353 return 0;
354 }
355 }
356 if (has_keyid_len (pattern))
357 kid = s->keyid;
358 else
359 kid = s->fpr;
360 if (kid && stristr (kid, pattern)) {
361 if (r_item)
362 *r_item = c;
363 *r_key = flags? c->pubpart->key : c->key;
364 return 0;
365 }
366 }
367 }
368 *r_key = NULL;
369 return gpg_error (GPG_ERR_INTERNAL);
370 } /* keycache_find_key */
371
372
373 gpgme_error_t
374 gpg_keycache_find_key (gpg_keycache_t ctx, const char *pattern,
375 int flags, gpgme_key_t *r_key)
376 {
377 return gpg_keycache_find_key2 (ctx, pattern, flags, r_key, NULL);
378 }
379
380
381 gpgme_error_t
382 gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,
383 void *opaque, const char *keyid)
384 {
385 struct keycache_s *c = NULL, *c_new=NULL;
386 gpgme_key_t key=NULL, fndkey=NULL;
387 gpgme_error_t err;
388 gpgme_ctx_t gctx;
389 gpg_keycache_t pub = (gpg_keycache_t)opaque;
390
391 err = gpgme_new (&gctx);
392 if (err)
393 return err;
394 err = gpgme_get_key (gctx, keyid, &key, is_sec);
395 gpgme_release (gctx);
396 if (err)
397 return err;
398 err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);
399 if (!err && c != NULL) {
400 log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);
401 gpgme_key_release (fndkey);
402 c->key = key;
403 c->flags = 0;
404 if (is_sec && pub != NULL &&
405 !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {
406 log_debug ("keycache update: set public part %p\r\n", fndkey);
407 c->pubpart->key = fndkey;
408 }
409 }
410 else {
411 log_debug ("keycache add: sync public part\r\n");
412 if (is_sec)
413 gpg_keycache_find_key2 (pub, keyid, 0, &fndkey, &c_new);
414 gpg_keycache_add_key (ctx, key, (void **)&c);
415 if (c != NULL && is_sec) {
416 log_debug ("keycache add: keyid=%s %p %p\r\n", keyid, c, fndkey);
417 c->pubpart = c_new;
418 if (c_new != NULL) {
419 c->pubpart->key = fndkey;
420 c->gloflags.is_protected = c_new->gloflags.is_protected;
421 c->gloflags.divert_to_card = c_new->gloflags.divert_to_card;
422 }
423 }
424 }
425 return 0;
426 }
427
428
429 /* Delete a key from the cache @ctx with the pattern @pattern.
430 Return value: 0 on success. */
431 gpgme_error_t
432 gpg_keycache_delete_key (gpg_keycache_t ctx, const char *pattern)
433 {
434 struct keycache_s *itm = NULL, *c;
435 gpgme_key_t key;
436 gpgme_error_t rc;
437
438 if (!ctx)
439 return gpg_error (GPG_ERR_INV_ARG);
440 rc = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
441 if (rc)
442 return rc;
443
444 c = ctx->item;
445 if (c->next == NULL) {
446 gpgme_key_release (itm->key);
447 if (itm)
448 free (itm);
449 ctx->item = NULL;
450 }
451 else {
452 while (c && c->next != itm)
453 c = c->next;
454 c->next = c->next->next;
455 gpgme_key_release (itm->key);
456 if (itm)
457 free (itm);
458 }
459 return 0;
460 }
461
462
463 /* Initialize the given cache @ctx. If @pattern is NULL, the entire keyring
464 will be added to the cache. @secret is 1 if the source is the secret keyring.
465 Return value: 0 on success. */
466 gpgme_error_t
467 gpg_keycache_init (gpg_keycache_t ctx, const char *pattern, int secret)
468 {
469 gpgme_error_t err;
470 gpgme_ctx_t c;
471 gpgme_key_t key;
472 int count = 0;
473
474 if (!ctx)
475 return gpg_error (GPG_ERR_INV_ARG);
476
477 err = gpgme_new (&c);
478 if (err)
479 return err;
480
481 gpgme_set_keylist_mode (c, GPGME_KEYLIST_MODE_SIGS);
482 err = gpgme_op_keylist_start (c, pattern, secret);
483 while(!err) {
484 err = gpgme_op_keylist_next (c, &key);
485 if (!err)
486 err = gpg_keycache_add_key (ctx, key, NULL);
487 if (ctx->cb)
488 ctx->cb (ctx->cb_value, _("Load GPG Keyrings..."), 0,
489 count++, ctx->cb_value2);
490 }
491 if (gpgme_err_code (err) == GPG_ERR_EOF)
492 err = gpg_error (GPG_ERR_NO_ERROR);
493 /* XXX: make sure the progress dialog is closed. */
494 gpgme_op_keylist_end (c);
495 gpgme_release (c);
496 return err;
497 }
498
499
500 /* XXX: kludge to see if the key is stored on a card. */
501 static int
502 key_divert_to_card (gpgme_key_t key)
503 {
504 gpgme_subkey_t k;
505 int n=0, n_alg=0, can_auth = 0;
506
507 for (k = key->subkeys; k; k = k->next) {
508 n++;
509 if (k->pubkey_algo == GPGME_PK_RSA && k->length == 1024)
510 n_alg++;
511 if (k->can_authenticate)
512 can_auth++;
513 }
514 if (n == 3 && n_alg == 3 && can_auth == 1)
515 return 1;
516 return 0;
517 }
518
519
520 gpgme_error_t
521 gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)
522 {
523 struct keycache_s *c, *c_sec;
524 gpgme_key_t key;
525
526 if (!pub || !sec)
527 return gpg_error (GPG_ERR_INV_ARG);
528
529 for (c=sec->item; c; c=c->next) {
530 if (!gpg_keycache_find_key2 (pub, c->key->subkeys->keyid, 0, &key, &c_sec)) {
531 c_sec->gloflags.is_protected = c->gloflags.is_protected;
532 c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;
533 if (!c->gloflags.divert_to_card)
534 c->gloflags.divert_to_card = key_divert_to_card (key);
535 c->pubpart = c_sec;
536 c->pubpart->key = key;
537 }
538 }
539 return 0;
540 }
541
542
543 /* Rewind the given cache @ctx to the begin. */
544 void
545 gpg_keycache_rewind (gpg_keycache_t ctx)
546 {
547 if (ctx)
548 ctx->pos = 0;
549 }
550
551
552
553 /* Return the number of elements in the cache @ctx. */
554 int
555 gpg_keycache_get_size (gpg_keycache_t ctx)
556 {
557 struct keycache_s *c;
558 int count = 0;
559
560 if (!ctx)
561 return 0;
562 for (c = ctx->item; c; c = c->next)
563 count++;
564 return count;
565 }
566
567
568 static gpgme_error_t
569 keycache_next_key (gpg_keycache_t ctx, int flags,
570 struct keycache_s **c, gpgme_key_t *r_key)
571 {
572 if (!ctx || !r_key)
573 return gpg_error (GPG_ERR_INV_ARG);
574
575 if (!ctx->pos)
576 ctx->tmp = ctx->item;
577
578 if (!ctx->tmp || !ctx->tmp->key) {
579 ctx->pos = 0;
580 *r_key = NULL;
581 return gpg_error (GPG_ERR_EOF);
582 }
583
584 *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;
585 *c = ctx->tmp = ctx->tmp->next;
586 ctx->pos++;
587
588 return 0;
589 }
590
591
592 /* Return the next key from the cache @ctx. The key will be returned
593 in @r_key. @flags can contain additional flags.
594 Return value: 0 on success. */
595 gpgme_error_t
596 gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)
597 {
598 struct keycache_s *c=NULL;
599 gpgme_error_t err = 0;
600
601 err = keycache_next_key (ctx, flags, &c, r_key);
602 return err;
603 }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26