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

Contents of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (show annotations)
Fri Oct 28 08:25:30 2005 UTC (19 years, 4 months ago) by werner
File size: 15220 byte(s)
Readded lost changes from revision 40

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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26