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

Contents of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 48 - (show annotations)
Mon Oct 31 21:14:11 2005 UTC (19 years, 4 months ago) by werner
File size: 15199 byte(s)
More changes.  Compiles again but there are at least gettext issues with
w32-gettext.c.  I can't get a gpg-error build with ENABLE_NLS.

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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26