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

Contents of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 41 - (show annotations)
Fri Oct 28 07:15:26 2005 UTC (19 years, 4 months ago) by twoaday
File size: 15150 byte(s)
A lot of bug fixes. See ChangeLog.

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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26